@oicl/openbridge-webcomponents 2.0.0-next.110 → 2.0.0-next.112
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/bundle/openbridge-webcomponents.bundle.js +2370 -1522
- package/bundle/openbridge-webcomponents.bundle.js.map +1 -1
- package/custom-elements.json +641 -7
- package/dist/automation/indicator-battery/indicator-battery.css.js +52 -0
- package/dist/automation/indicator-battery/indicator-battery.css.js.map +1 -0
- package/dist/automation/indicator-battery/indicator-battery.d.ts +65 -0
- package/dist/automation/indicator-battery/indicator-battery.d.ts.map +1 -0
- package/dist/automation/indicator-battery/indicator-battery.js +119 -0
- package/dist/automation/indicator-battery/indicator-battery.js.map +1 -0
- package/dist/automation/indicator-engine/indicator-engine.css.js +45 -0
- package/dist/automation/indicator-engine/indicator-engine.css.js.map +1 -0
- package/dist/automation/indicator-engine/indicator-engine.d.ts +34 -0
- package/dist/automation/indicator-engine/indicator-engine.d.ts.map +1 -0
- package/dist/automation/indicator-engine/indicator-engine.js +73 -0
- package/dist/automation/indicator-engine/indicator-engine.js.map +1 -0
- package/dist/automation/indicator-generator/indicator-generator-geometry.d.ts +30 -0
- package/dist/automation/indicator-generator/indicator-generator-geometry.d.ts.map +1 -0
- package/dist/automation/indicator-generator/indicator-generator-geometry.js +61 -0
- package/dist/automation/indicator-generator/indicator-generator-geometry.js.map +1 -0
- package/dist/automation/indicator-generator/indicator-generator.css.js +121 -0
- package/dist/automation/indicator-generator/indicator-generator.css.js.map +1 -0
- package/dist/automation/indicator-generator/indicator-generator.d.ts +57 -0
- package/dist/automation/indicator-generator/indicator-generator.d.ts.map +1 -0
- package/dist/automation/indicator-generator/indicator-generator.js +136 -0
- package/dist/automation/indicator-generator/indicator-generator.js.map +1 -0
- package/dist/automation/indicator-shared/linear-indicator.d.ts +46 -0
- package/dist/automation/indicator-shared/linear-indicator.d.ts.map +1 -0
- package/dist/automation/indicator-shared/linear-indicator.js +175 -0
- package/dist/automation/indicator-shared/linear-indicator.js.map +1 -0
- package/dist/automation/indicator-tank-atmospheric/indicator-tank-atmospheric.css.js +48 -0
- package/dist/automation/indicator-tank-atmospheric/indicator-tank-atmospheric.css.js.map +1 -0
- package/dist/automation/indicator-tank-atmospheric/indicator-tank-atmospheric.d.ts +65 -0
- package/dist/automation/indicator-tank-atmospheric/indicator-tank-atmospheric.d.ts.map +1 -0
- package/dist/automation/indicator-tank-atmospheric/indicator-tank-atmospheric.js +105 -0
- package/dist/automation/indicator-tank-atmospheric/indicator-tank-atmospheric.js.map +1 -0
- package/dist/navigation-instruments/compass/compass.d.ts +1 -1
- package/dist/navigation-instruments/compass/compass.d.ts.map +1 -1
- package/dist/navigation-instruments/compass/compass.js +1 -1
- package/dist/navigation-instruments/compass/compass.js.map +1 -1
- package/dist/navigation-instruments/current/current.d.ts +25 -0
- package/dist/navigation-instruments/current/current.d.ts.map +1 -1
- package/dist/navigation-instruments/current/current.js +25 -4
- package/dist/navigation-instruments/current/current.js.map +1 -1
- package/dist/navigation-instruments/heading/heading.js +1 -1
- package/dist/navigation-instruments/heading/heading.js.map +1 -1
- package/dist/navigation-instruments/pitch-roll-heave/pitch-roll-heave.d.ts +6 -0
- package/dist/navigation-instruments/pitch-roll-heave/pitch-roll-heave.d.ts.map +1 -1
- package/dist/navigation-instruments/pitch-roll-heave/pitch-roll-heave.js +8 -1
- package/dist/navigation-instruments/pitch-roll-heave/pitch-roll-heave.js.map +1 -1
- package/dist/navigation-instruments/rate-of-turn/rate-of-turn.d.ts +5 -2
- 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.map +1 -1
- package/dist/navigation-instruments/top-view-propulsion/top-view-propulsion.d.ts +6 -0
- package/dist/navigation-instruments/top-view-propulsion/top-view-propulsion.d.ts.map +1 -1
- package/dist/navigation-instruments/top-view-propulsion/top-view-propulsion.js +19 -4
- package/dist/navigation-instruments/top-view-propulsion/top-view-propulsion.js.map +1 -1
- package/dist/navigation-instruments/watch/environment.d.ts +8 -0
- package/dist/navigation-instruments/watch/environment.d.ts.map +1 -1
- package/dist/navigation-instruments/watch/environment.js +3 -0
- package/dist/navigation-instruments/watch/environment.js.map +1 -1
- package/dist/navigation-instruments/watch/force-pattern.d.ts +20 -2
- package/dist/navigation-instruments/watch/force-pattern.d.ts.map +1 -1
- package/dist/navigation-instruments/watch/force-pattern.js +12 -5
- package/dist/navigation-instruments/watch/force-pattern.js.map +1 -1
- package/dist/navigation-instruments/watch/watch.d.ts.map +1 -1
- package/dist/navigation-instruments/watch/watch.js +6 -4
- package/dist/navigation-instruments/watch/watch.js.map +1 -1
- package/dist/navigation-instruments/wind/wind.d.ts +5 -2
- package/dist/navigation-instruments/wind/wind.d.ts.map +1 -1
- package/dist/navigation-instruments/wind/wind.js +5 -1
- package/dist/navigation-instruments/wind/wind.js.map +1 -1
- package/package.json +1 -1
|
@@ -200,9 +200,16 @@ let ObcPitchRollHeave = class extends LitElement {
|
|
|
200
200
|
* `obc-watch` renders its crosshair after the bands, i.e. on top of them.
|
|
201
201
|
* Drawing it here puts it under the watch layer, so the bands and the heave
|
|
202
202
|
* column mask it naturally.
|
|
203
|
+
*
|
|
204
|
+
* In `single-scale` nothing frames the segment above the vessel (the other
|
|
205
|
+
* three arms end under the pitch band, roll band and heave column), so the
|
|
206
|
+
* vertical arm stops at the centre instead of continuing upward. In
|
|
207
|
+
* `dual-scale` the top roll band gives it a natural endpoint, so the full
|
|
208
|
+
* arm is kept.
|
|
203
209
|
*/
|
|
204
210
|
renderCrosshair() {
|
|
205
211
|
const r = OUTER_RING_RADIUS;
|
|
212
|
+
const yTop = this.isDualScale ? -r : 0;
|
|
206
213
|
return svg`
|
|
207
214
|
<line
|
|
208
215
|
x1=${-r} y1="0" x2=${r} y2="0"
|
|
@@ -210,7 +217,7 @@ let ObcPitchRollHeave = class extends LitElement {
|
|
|
210
217
|
vector-effect="non-scaling-stroke"
|
|
211
218
|
/>
|
|
212
219
|
<line
|
|
213
|
-
x1="0" y1=${
|
|
220
|
+
x1="0" y1=${yTop} x2="0" y2=${r}
|
|
214
221
|
stroke="var(--instrument-frame-tertiary-color)"
|
|
215
222
|
vector-effect="non-scaling-stroke"
|
|
216
223
|
/>
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pitch-roll-heave.js","sources":["../../../src/navigation-instruments/pitch-roll-heave/pitch-roll-heave.ts"],"sourcesContent":["import {LitElement, css, html, nothing, svg, type SVGTemplateResult} from 'lit';\nimport {property} from 'lit/decorators.js';\nimport '../watch/watch.js';\nimport {\n VesselImage,\n VesselImageSize,\n WatchCircleType,\n type WatchArea,\n OUTER_RING_RADIUS,\n innerRingRadiusFor,\n vesselImages,\n} from '../watch/watch.js';\nimport {arcTickmarks, TickmarkType, type Tickmark} from '../watch/tickmark.js';\nimport {AdviceState, AdviceType, type AngleAdviceRaw} from '../watch/advice.js';\nimport {customElement} from '../../decorator.js';\nimport {Priority} from '../types.js';\nimport {\n CenterReadoutArrangement,\n centerReadoutStyles,\n renderCenterReadouts,\n} from '../readout/center-readout.js';\nimport {ReadoutSize} from '../readout/readout.js';\nimport {\n computeZoomToFitArcFrame,\n normalizeArcAngle,\n shiftArcFrameToOuterEdge,\n} from '../../svghelpers/arc-frame.js';\nimport {\n linearTickInterval,\n watchfaceLinear,\n} from '../../building-blocks/instrument-linear/instrument-linear.js';\nimport type {\n LinearAdvice,\n LinearAdviceRaw,\n} from '../../building-blocks/instrument-linear/advice.js';\n\nexport enum ObcPitchRollHeaveType {\n /** Pitch on the right, roll at the bottom, heave in the left band slot. */\n singleScale = 'single-scale',\n /** Pitch and roll mirrored onto both sides, heave centred. */\n dualScale = 'dual-scale',\n}\n\nexport enum PitchRollHeavePriorityElement {\n pitch = 'pitch',\n roll = 'roll',\n heave = 'heave',\n}\n\n/** Half-side of the centre overlay viewBox in SVG units. */\nconst CENTRE_HALF = 200;\n\n/**\n * Minimum diagonal clearance, in central-layer pixels, between the zoomed\n * heave column and the adjacent roll band. Matches the constant\n * `obc-pitch-roll` uses between its own adjacent arcs.\n */\nconst CORNER_GAP_PX = 32;\n\n/** Numerical safety floor when an axis arc has to collapse for clearance. */\nconst MIN_ARC_HALF_DEG = 2;\n\n/** Width of the tick lane inside the heave column, in SVG units. */\nconst HEAVE_SCALE_WIDTH = 24;\n\n/** Band thickness at the natural, un-zoomed radii. */\nconst NOMINAL_BAND =\n OUTER_RING_RADIUS - innerRingRadiusFor(WatchCircleType.double);\n\n/**\n * Clearance kept between the centred (`dual-scale`) heave column's corners and\n * the surrounding band, in central-layer pixels. Sized so the un-zoomed\n * default is untouched — there the corner sits 13.2 units inside the free\n * radius — while the tighter zoomed layout is pulled back off the bands.\n */\nconst HEAVE_CENTRE_GAP_PX = 10;\n\n/**\n * The band slot the heave column fills, in central-layer coordinates.\n *\n * `outerR`/`innerR` bound the slot radially; `capRadius` is the radius of the\n * pitch arc's outer edge about its own origin, which is what the column's\n * height is measured against so the two line up. Un-zoomed the two radii\n * coincide; under zoom the arc is drawn on a shifted sub-watch and they differ.\n */\ninterface HeaveBand {\n outerR: number;\n innerR: number;\n capRadius: number;\n pitchDeg: number;\n}\n\n/**\n * Natural size of the heave column: as thick as the band slot, and tall enough\n * that its top and bottom edges sit level with the pitch arc's end caps.\n */\nfunction heaveColumnSize(band: HeaveBand): {width: number; height: number} {\n return {\n width: band.outerR - band.innerR,\n height: 2 * band.capRadius * Math.sin((band.pitchDeg * Math.PI) / 180),\n };\n}\n\n/**\n * Distance from a point to an axis-aligned rectangle; 0 when the point is\n * inside. Used to keep the zoomed roll band clear of the heave column, which\n * — unlike the arc-to-arc case — is a rectangle, so a corner may clear it on\n * one axis alone.\n */\nfunction distanceToRect(\n px: number,\n py: number,\n x0: number,\n y0: number,\n x1: number,\n y1: number\n): number {\n const dx = Math.max(0, x0 - px, px - x1);\n const dy = Math.max(0, y0 - py, py - y1);\n return Math.hypot(dx, dy);\n}\n\n/**\n * `<obc-pitch-roll-heave>` — Combined pitch, roll and heave indicator.\n *\n * Places a pitch arc, a roll arc and a linear heave column around one watch\n * face. The heave column occupies the same radial slot as the arcs, and its\n * height is derived from the pitch arc so its top and bottom edges sit level\n * with the pitch arc's end caps.\n *\n * Variants (`type`):\n * - `single-scale` (default) — pitch on the right, roll at the bottom, heave in\n * the left slot, vessel silhouettes in the centre.\n * - `dual-scale` — pitch and roll mirrored onto the opposite sides, with the\n * heave column moved to the centre.\n *\n * Set `hasReadout` to replace the centre content with stacked pitch, roll and\n * heave readouts, and `zoomToFitArc` to enlarge narrow arcs so they fill the\n * available space.\n *\n * @element obc-pitch-roll-heave\n * @experimental\n */\n@customElement('obc-pitch-roll-heave')\nexport class ObcPitchRollHeave extends LitElement {\n @property({type: String}) type: ObcPitchRollHeaveType =\n ObcPitchRollHeaveType.singleScale;\n\n @property({type: Number}) pitch = 0;\n @property({type: Number}) roll = 0;\n @property({type: Number}) heave = 0;\n @property({type: Number}) minAvgPitch = 0;\n @property({type: Number}) maxAvgPitch = 0;\n @property({type: Number}) minAvgRoll = 0;\n @property({type: Number}) maxAvgRoll = 0;\n @property({type: Number}) minTrendHeave = 0;\n @property({type: Number}) maxTrendHeave = 0;\n /** Half-extent of the heave scale in metres; the column spans `±heaveRange`. */\n @property({type: Number}) heaveRange = 10;\n\n /**\n * Half-extent of the pitch arc in degrees. Also drives the heave column\n * height, which is `2 · outerRadius · sin(pitchArcAngle)` so the column's\n * edges stay level with the pitch arc's end caps.\n */\n @property({type: Number}) pitchArcAngle = 30;\n /** Half-extent of the roll arc in degrees. */\n @property({type: Number}) rollArcAngle = 45;\n @property({type: Boolean}) zoomToFitArc = false;\n\n /**\n * Replaces the centre content with stacked pitch, roll and heave readouts.\n * Ignored when `type` is `dual-scale`, where the heave column occupies the\n * centre.\n * @availableWhen type==singleScale\n */\n @property({type: Boolean}) hasReadout = false;\n /** @availableWhen hasReadout==true */\n @property({type: String}) pitchLabel = 'Pitch';\n /** @availableWhen hasReadout==true */\n @property({type: String}) rollLabel = 'Roll';\n /** @availableWhen hasReadout==true */\n @property({type: String}) heaveLabel = 'Heave';\n /**\n * Unit shown in the pitch and roll readouts.\n * @availableWhen hasReadout==true\n */\n @property({type: String}) unit = 'DEG';\n /**\n * Unit shown in the heave readout.\n * @availableWhen hasReadout==true\n */\n @property({type: String}) heaveUnit = 'm';\n /** @availableWhen hasReadout==true */\n @property({type: Number}) fractionDigits = 0;\n\n /** @availableWhen type==singleScale && hasReadout==false */\n @property({type: String}) vesselImageFore: VesselImage = VesselImage.psvFore;\n /** @availableWhen type==singleScale && hasReadout==false */\n @property({type: String}) vesselImageSide: VesselImage = VesselImage.psvSide;\n /** @availableWhen type==singleScale && hasReadout==false */\n @property({type: Number}) scaleForeImage = 1;\n\n @property({type: Number}) maxPitchAdvice: number | undefined = undefined;\n @property({type: Number}) maxRollAdvice: number | undefined = undefined;\n /** @availableWhen maxPitchAdvice!=undefined */\n @property({type: Boolean}) triggerPitchAdvice = false;\n /** @availableWhen maxRollAdvice!=undefined */\n @property({type: Boolean}) triggerRollAdvice = false;\n @property({type: Array}) heaveAdvice: LinearAdvice[] = [];\n\n @property({type: String}) priority: Priority = Priority.regular;\n @property({type: Array, attribute: false})\n priorityElements: PitchRollHeavePriorityElement[] = [\n PitchRollHeavePriorityElement.pitch,\n PitchRollHeavePriorityElement.roll,\n PitchRollHeavePriorityElement.heave,\n ];\n\n private priorityFor(element: PitchRollHeavePriorityElement): Priority {\n const selected = Array.isArray(this.priorityElements)\n ? this.priorityElements\n : [];\n return selected.includes(element) ? this.priority : Priority.regular;\n }\n\n private needleColor(element: PitchRollHeavePriorityElement): string {\n return this.priorityFor(element) === Priority.enhanced\n ? 'var(--instrument-enhanced-secondary-color)'\n : 'var(--instrument-regular-secondary-color)';\n }\n\n private barColor(element: PitchRollHeavePriorityElement): string {\n return this.priorityFor(element) === Priority.enhanced\n ? 'var(--instrument-enhanced-tertiary-color)'\n : 'var(--instrument-regular-tertiary-color)';\n }\n\n private get normalizedScaleForeImage(): number {\n if (!Number.isFinite(this.scaleForeImage)) {\n return 1;\n }\n return Math.max(0, Math.min(2, this.scaleForeImage));\n }\n\n private get isDualScale(): boolean {\n return this.type === ObcPitchRollHeaveType.dualScale;\n }\n\n /** The centre readouts replace the vessels; never available in dual scale. */\n private get showsReadout(): boolean {\n return this.hasReadout && !this.isDualScale;\n }\n\n /**\n * Pitch half-extent, capped so a roll arc of the minimum size still fits in\n * the remaining quadrant.\n */\n private get requestedPitchArcAngle(): number {\n return Math.min(\n 90 - MIN_ARC_HALF_DEG,\n normalizeArcAngle(this.pitchArcAngle, 30)\n );\n }\n\n /**\n * Roll half-extent, clamped so the pitch and roll arcs cannot meet: the two\n * diagonal gaps each span `90 - pitch - roll` degrees, so the pair has to\n * stay under 90° combined.\n */\n private get requestedRollArcAngle(): number {\n const roll = normalizeArcAngle(this.rollArcAngle, 45);\n const headroom = 90 - this.requestedPitchArcAngle;\n return Math.max(MIN_ARC_HALF_DEG, Math.min(roll, headroom));\n }\n\n override render() {\n const pitchReq = this.requestedPitchArcAngle;\n const rollReq = this.requestedRollArcAngle;\n const overlayViewBox = `-${CENTRE_HALF} -${CENTRE_HALF} ${CENTRE_HALF * 2} ${CENTRE_HALF * 2}`;\n\n const layout = this.zoomToFitArc\n ? this.zoomLayout(pitchReq, rollReq)\n : undefined;\n const band: HeaveBand = layout?.band ?? {\n outerR: OUTER_RING_RADIUS,\n innerR: innerRingRadiusFor(WatchCircleType.double),\n capRadius: OUTER_RING_RADIUS,\n pitchDeg: pitchReq,\n };\n\n return html`\n <div class=\"container\">\n <svg viewBox=${overlayViewBox}>\n ${this.showsReadout ? nothing : this.renderCrosshair()}\n ${this.renderOverlayVessels()}\n ${this.zoomToFitArc || this.isDualScale\n ? nothing\n : this.renderComplement(pitchReq)}\n ${this.renderHeaveColumn(band)}\n </svg>\n ${layout\n ? this.renderZoomedArcs(layout)\n : this.renderFullWatch(pitchReq, rollReq)}\n ${this.showsReadout\n ? html`<div class=\"readout\">\n ${renderCenterReadouts(\n [\n {\n value: this.pitch,\n label: this.pitchLabel,\n unit: this.unit,\n fractionDigits: this.fractionDigits,\n size: ReadoutSize.large,\n priority: this.priorityFor(\n PitchRollHeavePriorityElement.pitch\n ),\n },\n {\n value: this.roll,\n label: this.rollLabel,\n unit: this.unit,\n fractionDigits: this.fractionDigits,\n size: ReadoutSize.large,\n priority: this.priorityFor(\n PitchRollHeavePriorityElement.roll\n ),\n },\n {\n value: this.heave,\n label: this.heaveLabel,\n unit: this.heaveUnit,\n fractionDigits: this.fractionDigits,\n size: ReadoutSize.large,\n priority: this.priorityFor(\n PitchRollHeavePriorityElement.heave\n ),\n },\n ],\n CenterReadoutArrangement.stacked\n )}\n </div>`\n : nothing}\n </div>\n `;\n }\n\n /**\n * Crosshair drawn on the overlay rather than through `obc-watch`'s own\n * `crosshairEnabled`: the design has the arc bands covering the arms, but\n * `obc-watch` renders its crosshair after the bands, i.e. on top of them.\n * Drawing it here puts it under the watch layer, so the bands and the heave\n * column mask it naturally.\n */\n private renderCrosshair(): SVGTemplateResult {\n const r = OUTER_RING_RADIUS;\n return svg`\n <line\n x1=${-r} y1=\"0\" x2=${r} y2=\"0\"\n stroke=\"var(--instrument-frame-tertiary-color)\"\n vector-effect=\"non-scaling-stroke\"\n />\n <line\n x1=\"0\" y1=${-r} x2=\"0\" y2=${r}\n stroke=\"var(--instrument-frame-tertiary-color)\"\n vector-effect=\"non-scaling-stroke\"\n />\n `;\n }\n\n /**\n * Vessel silhouettes on the centre layer. Only needed under zoom — the\n * un-zoomed path hands them to `obc-watch` via `vessels`, while the zoomed\n * sub-watches have no room for them.\n */\n private renderOverlayVessels(): SVGTemplateResult | typeof nothing {\n if (!this.zoomToFitArc || this.isDualScale || this.showsReadout) {\n return nothing;\n }\n const vesselScale = 224 / 160;\n return svg`\n <g style=\"transform: rotate(${this.pitch}deg) scale(${vesselScale}) translate(-80px, -80px);\">\n ${vesselImages[this.vesselImageSide]}\n </g>\n <g style=\"transform: rotate(${this.roll}deg) scale(${vesselScale * this.normalizedScaleForeImage}) translate(-80px, -80px);\">\n ${vesselImages[this.vesselImageFore]}\n </g>\n `;\n }\n\n /**\n * Thin ring bridging the empty span across the top, from where the heave\n * column's upper edge crosses the outer ring round to the pitch arc's start.\n * Because the column height is derived from the pitch arc, both ends land at\n * `±pitchArcAngle` off the vertical, making the ring symmetric. The two\n * diagonal gaps lower down are left open by design.\n */\n private renderComplement(pitchDeg: number): SVGTemplateResult {\n const r = OUTER_RING_RADIUS;\n const rad = (pitchDeg * Math.PI) / 180;\n // Ring runs clockwise from (270 + pitchDeg) through 0 to (90 - pitchDeg).\n const x1 = -r * Math.cos(rad);\n const y1 = -r * Math.sin(rad);\n const x2 = r * Math.cos(rad);\n const y2 = -r * Math.sin(rad);\n return svg`\n <path\n d=\"M ${x1} ${y1} A ${r} ${r} 0 0 1 ${x2} ${y2}\"\n fill=\"none\"\n stroke=\"var(--instrument-frame-tertiary-color)\"\n vector-effect=\"non-scaling-stroke\"\n />\n `;\n }\n\n /**\n * Linear heave scale, built from the same building block `obc-heave` uses.\n *\n * The column fills the band's radial slot, so its width equals the band\n * thickness and its height keeps its top and bottom edges level with the\n * pitch arc's end caps. In `single-scale` it sits in the left slot and is\n * mirrored so the tick lane faces outward; in `dual-scale` it moves to the\n * centre, unmirrored, and shrinks if the zoomed bands leave too little room.\n */\n private renderHeaveColumn(band: HeaveBand): SVGTemplateResult {\n const {width, height: naturalHeight} = heaveColumnSize(band);\n let height = naturalHeight;\n let offsetX = -(band.outerR + band.innerR) / 2;\n\n if (this.isDualScale) {\n offsetX = 0;\n // The centred column has to stay inside whatever the bands leave free.\n // Only the height gives way: the column's thickness reads as a match for\n // the band thickness, and shrinking both would break that.\n const free = band.innerR - HEAVE_CENTRE_GAP_PX;\n const halfWidth = width / 2;\n const maxHalfHeight =\n free > halfWidth ? Math.sqrt(free * free - halfWidth * halfWidth) : 0;\n height = Math.min(height, 2 * maxHalfHeight);\n }\n\n const scaleWidth = HEAVE_SCALE_WIDTH * Math.min(1, width / NOMINAL_BAND);\n\n const gauge = watchfaceLinear(\n {\n height,\n width,\n scaleWidth,\n minValue: -this.heaveRange,\n maxValue: this.heaveRange,\n },\n [{min: this.minTrendHeave, max: this.maxTrendHeave}],\n {value: this.heave},\n {container: 'var(--instrument-frame-primary-color)'},\n {\n hideContainer: false,\n off: false,\n priority: this.priorityFor(PitchRollHeavePriorityElement.heave),\n },\n {\n mainTickmarks: [],\n primaryTickmarkInterval: 0,\n secondaryTickmarkInterval: linearTickInterval(height, this.heaveRange),\n },\n this.heaveAdvices\n );\n\n const mirror = this.isDualScale ? '' : ' scale(-1, 1)';\n return svg`<g transform=\"translate(${offsetX}, 0)${mirror}\">${gauge}</g>`;\n }\n\n private get heaveAdvices(): LinearAdviceRaw[] {\n return this.heaveAdvice.map((advice) => {\n const isActive =\n this.maxTrendHeave >= advice.min && this.minTrendHeave <= advice.max;\n const state = isActive\n ? AdviceState.triggered\n : advice.hinted\n ? AdviceState.hinted\n : AdviceState.regular;\n return {...advice, state} satisfies LinearAdviceRaw;\n });\n }\n\n /**\n * Zoom-fit geometry, computed once per render and shared by the arc layer\n * and the heave column.\n *\n * Frames are built at the REQUESTED half-extents with the same math as\n * `obc-pitch` / `obc-roll`, so each sub-watch matches its standalone\n * equivalent. Two clearance passes then shorten only the *rendered* arcs —\n * the frames stay untouched, so band thickness, position and zoom level are\n * preserved:\n *\n * 1. pitch vs roll at the diagonal, ratio-preserving, exactly as\n * `obc-pitch-roll` does it;\n * 2. roll vs the heave column, `single-scale` only, shortening the roll arc\n * alone. Because the column's height follows the pitch arc, pass 1 already\n * pulls the column in whenever pitch shrinks, so pitch needs no second\n * pass.\n */\n private zoomLayout(pitchReq: number, rollReq: number) {\n const ext = 48;\n const targetSize = (176 + ext) * 2;\n const innerNat = innerRingRadiusFor(WatchCircleType.double);\n const buildFrame = (halfDeg: number) => {\n const areas: WatchArea[] = [\n {\n startAngle: -halfDeg,\n endAngle: halfDeg,\n roundOutsideCut: true,\n roundInsideCut: true,\n },\n ];\n const baseFrame = computeZoomToFitArcFrame({\n areas,\n outerRadius: OUTER_RING_RADIUS,\n innerRadius: innerNat,\n extension: ext,\n targetSize,\n });\n const subArcFrame = shiftArcFrameToOuterEdge(\n baseFrame,\n OUTER_RING_RADIUS + baseFrame.radiusOffset,\n OUTER_RING_RADIUS,\n CENTRE_HALF\n );\n const scale = (CENTRE_HALF * 2) / subArcFrame.width;\n const outerR = (OUTER_RING_RADIUS + baseFrame.radiusOffset) * scale;\n const innerR = (innerNat + baseFrame.radiusOffset) * scale;\n return {subArcFrame, outerR, innerR};\n };\n const pitchFrame = buildFrame(pitchReq);\n const rollFrame = buildFrame(rollReq);\n\n const OR = OUTER_RING_RADIUS;\n const toRad = (deg: number) => (deg * Math.PI) / 180;\n const signedDist = (\n px: number,\n py: number,\n qx: number,\n qy: number\n ): number => {\n const dx = qx - px;\n const dy = qy - py;\n const mag = Math.hypot(dx, dy);\n return dx > 0 && dy > 0 ? mag : -mag;\n };\n // Diagonal gap between two adjacent cardinal bands. All such gaps in this\n // layout are congruent, so one pair stands in for the rest.\n const minGap = (apRad: number, arRad: number): number => {\n const cosP = Math.cos(apRad);\n const sinP = Math.sin(apRad);\n const cosR = Math.cos(arRad);\n const sinR = Math.sin(arRad);\n const p1x = pitchFrame.innerR * sinP;\n const p1y = pitchFrame.outerR - OR - pitchFrame.innerR * cosP;\n const p2x = pitchFrame.outerR * sinP;\n const p2y = pitchFrame.outerR - OR - pitchFrame.outerR * cosP;\n const q1x = OR - rollFrame.outerR + rollFrame.innerR * cosR;\n const q1y = -rollFrame.innerR * sinR;\n const q2x = OR - rollFrame.outerR + rollFrame.outerR * cosR;\n const q2y = -rollFrame.outerR * sinR;\n return Math.min(\n signedDist(p1x, p1y, q1x, q1y),\n signedDist(p2x, p2y, q2x, q2y)\n );\n };\n\n let aP = toRad(pitchReq);\n let aR = toRad(rollReq);\n if (minGap(aP, aR) < CORNER_GAP_PX) {\n let lo = 0;\n let hi = 1;\n for (let i = 0; i < 40; i++) {\n const mid = (lo + hi) / 2;\n if (minGap(aP * mid, aR * mid) >= CORNER_GAP_PX) {\n lo = mid;\n } else {\n hi = mid;\n }\n }\n aP *= lo;\n aR *= lo;\n }\n const pitchClampedDeg = Math.max(MIN_ARC_HALF_DEG, (aP * 180) / Math.PI);\n let rollClampedDeg = Math.max(MIN_ARC_HALF_DEG, (aR * 180) / Math.PI);\n\n const bandFor = (pitchDeg: number): HeaveBand => ({\n outerR: OR,\n innerR: OR - (pitchFrame.outerR - pitchFrame.innerR),\n capRadius: pitchFrame.outerR,\n pitchDeg,\n });\n\n if (!this.isDualScale) {\n // Roll's left end caps versus the heave column rectangle. Shrinking the\n // roll arc moves both caps toward the bottom cardinal, away from the\n // column, so the gap grows monotonically as the scalar shrinks.\n const band = bandFor(pitchClampedDeg);\n const {width, height} = heaveColumnSize(band);\n const x1 = -band.innerR;\n const x0 = x1 - width;\n const y1 = height / 2;\n const heaveGap = (arRad: number): number => {\n const cosR = Math.cos(arRad);\n const sinR = Math.sin(arRad);\n const outerX = -rollFrame.outerR * sinR;\n const outerY = OR - rollFrame.outerR + rollFrame.outerR * cosR;\n const innerX = -rollFrame.innerR * sinR;\n const innerY = OR - rollFrame.outerR + rollFrame.innerR * cosR;\n return Math.min(\n distanceToRect(outerX, outerY, x0, -y1, x1, y1),\n distanceToRect(innerX, innerY, x0, -y1, x1, y1)\n );\n };\n if (heaveGap(toRad(rollClampedDeg)) < CORNER_GAP_PX) {\n let lo = 0;\n let hi = rollClampedDeg;\n for (let i = 0; i < 40; i++) {\n const mid = (lo + hi) / 2;\n if (heaveGap(toRad(mid)) >= CORNER_GAP_PX) {\n lo = mid;\n } else {\n hi = mid;\n }\n }\n rollClampedDeg = Math.max(MIN_ARC_HALF_DEG, lo);\n }\n }\n\n return {\n pitchFrame,\n rollFrame,\n pitchClampedDeg,\n rollClampedDeg,\n band: bandFor(pitchClampedDeg),\n };\n }\n\n /**\n * Zoomed-arc layer: CSS-rotated `<obc-watch>` instances, each holding a\n * single arc rendered at the watch's natural top and rotated onto its\n * cardinal. `single-scale` places pitch right and roll bottom; `dual-scale`\n * mirrors both. The heave column lives on the centre overlay.\n */\n private renderZoomedArcs(layout: ReturnType<typeof this.zoomLayout>) {\n const {pitchFrame, rollFrame, pitchClampedDeg, rollClampedDeg} = layout;\n\n const subAreas = (halfDeg: number): WatchArea[] => [\n {\n startAngle: -halfDeg,\n endAngle: halfDeg,\n roundOutsideCut: true,\n roundInsideCut: true,\n },\n ];\n\n // Clip each sub-watch to the sector its (possibly shortened) arc covers so\n // the indicator cannot leak past the visible band.\n const sectorClip = (\n halfDeg: number,\n frame: typeof rollFrame.subArcFrame\n ): string => {\n const oxPct = (-frame.x / frame.width) * 100;\n const oyPct = (-frame.y / frame.height) * 100;\n const dxPct = oyPct * Math.tan((halfDeg * Math.PI) / 180);\n const lx = Math.max(0, oxPct - dxPct);\n const rx = Math.min(100, oxPct + dxPct);\n return `polygon(${oxPct}% ${oyPct}%, ${lx}% 0%, ${rx}% 0%)`;\n };\n\n const axis = (\n element: PitchRollHeavePriorityElement,\n frame: typeof rollFrame,\n halfDeg: number,\n value: number,\n avgMin: number,\n avgMax: number,\n max: number | undefined,\n trigger: boolean,\n cap: number\n ) => ({\n arcFrame: frame.subArcFrame,\n areas: subAreas(halfDeg),\n barAreas: [\n {\n startAngle: avgMin,\n endAngle: avgMax,\n fillColor: this.barColor(element),\n },\n ],\n needles: [\n {\n angle: value,\n fillColor: this.needleColor(element),\n strokeColor: 'var(--border-silhouette-color)',\n },\n ],\n advices: this.subAdvices(halfDeg, max, trigger, cap),\n tickmarks: [\n {angle: 0, type: TickmarkType.main},\n ...arcTickmarks(0, halfDeg),\n ],\n clipPath: sectorClip(halfDeg, frame.subArcFrame),\n });\n\n const pitchAxis = axis(\n PitchRollHeavePriorityElement.pitch,\n pitchFrame,\n pitchClampedDeg,\n this.pitch,\n this.minAvgPitch,\n this.maxAvgPitch,\n this.maxPitchAdvice,\n this.triggerPitchAdvice,\n 30\n );\n const rollAxis = axis(\n PitchRollHeavePriorityElement.roll,\n rollFrame,\n rollClampedDeg,\n this.roll,\n this.minAvgRoll,\n this.maxAvgRoll,\n this.maxRollAdvice,\n this.triggerRollAdvice,\n 45\n );\n\n const subWatch = (rotation: number, a: typeof pitchAxis) => html`\n <obc-watch\n class=\"sub-watch\"\n style=\"transform: rotate(${rotation}deg); clip-path: ${a.clipPath};\"\n .watchCircleType=${WatchCircleType.double}\n .zoomToFitArc=${true}\n .arcFrame=${a.arcFrame}\n .areas=${a.areas}\n .barAreas=${a.barAreas}\n .needles=${a.needles}\n .vessels=${[]}\n .tickmarks=${a.tickmarks}\n .advices=${a.advices}\n ></obc-watch>\n `;\n\n return html`\n ${subWatch(90, pitchAxis)} ${subWatch(180, rollAxis)}\n ${this.isDualScale\n ? html`${subWatch(270, pitchAxis)} ${subWatch(0, rollAxis)}`\n : nothing}\n `;\n }\n\n /** Caution bands for one sub-watch axis, at sub-watch-local angles. */\n private subAdvices(\n halfDeg: number,\n max: number | undefined,\n trigger: boolean,\n cap: number\n ): AngleAdviceRaw[] {\n if (max === undefined) return [];\n const outer = Math.min(halfDeg, cap);\n const inner = Math.min(max, outer);\n const state = trigger ? AdviceState.triggered : AdviceState.regular;\n return [\n {\n minAngle: -outer,\n maxAngle: -inner,\n type: AdviceType.caution,\n state,\n hideMinTickmark: true,\n },\n {\n minAngle: inner,\n maxAngle: outer,\n type: AdviceType.caution,\n state,\n hideMaxTickmark: true,\n },\n ];\n }\n\n /** Areas, tickmarks, bars and needles for the un-zoomed single watch. */\n private renderFullWatch(pitchDeg: number, rollDeg: number) {\n const arc = (center: number, half: number): WatchArea => ({\n startAngle: center - half,\n endAngle: center + half,\n roundOutsideCut: true,\n roundInsideCut: true,\n });\n\n const areas: WatchArea[] = [arc(90, pitchDeg), arc(180, rollDeg)];\n const tickmarks: Tickmark[] = [\n {angle: 90, type: TickmarkType.main},\n {angle: 180, type: TickmarkType.main},\n ...arcTickmarks(90, pitchDeg),\n ...arcTickmarks(180, rollDeg),\n ];\n const barAreas = [\n {\n startAngle: 90 + this.minAvgPitch,\n endAngle: 90 + this.maxAvgPitch,\n fillColor: this.barColor(PitchRollHeavePriorityElement.pitch),\n },\n {\n startAngle: 180 + this.minAvgRoll,\n endAngle: 180 + this.maxAvgRoll,\n fillColor: this.barColor(PitchRollHeavePriorityElement.roll),\n },\n ];\n const needles = [\n {\n angle: 90 + this.pitch,\n fillColor: this.needleColor(PitchRollHeavePriorityElement.pitch),\n strokeColor: 'var(--border-silhouette-color)',\n },\n {\n angle: 180 + this.roll,\n fillColor: this.needleColor(PitchRollHeavePriorityElement.roll),\n strokeColor: 'var(--border-silhouette-color)',\n },\n ];\n\n if (this.isDualScale) {\n areas.push(arc(270, pitchDeg), arc(0, rollDeg));\n tickmarks.push(\n {angle: 270, type: TickmarkType.main},\n {angle: 0, type: TickmarkType.main},\n ...arcTickmarks(270, pitchDeg),\n ...arcTickmarks(0, rollDeg)\n );\n barAreas.push(\n {\n startAngle: 270 + this.minAvgPitch,\n endAngle: 270 + this.maxAvgPitch,\n fillColor: this.barColor(PitchRollHeavePriorityElement.pitch),\n },\n {\n startAngle: this.minAvgRoll,\n endAngle: this.maxAvgRoll,\n fillColor: this.barColor(PitchRollHeavePriorityElement.roll),\n }\n );\n needles.push(\n {\n angle: 270 + this.pitch,\n fillColor: this.needleColor(PitchRollHeavePriorityElement.pitch),\n strokeColor: 'var(--border-silhouette-color)',\n },\n {\n angle: this.roll,\n fillColor: this.needleColor(PitchRollHeavePriorityElement.roll),\n strokeColor: 'var(--border-silhouette-color)',\n }\n );\n }\n\n return html`\n <obc-watch\n .watchCircleType=${WatchCircleType.double}\n .zoomToFitArc=${false}\n .areas=${areas}\n .barAreas=${barAreas}\n .needles=${needles}\n .vessels=${this.isDualScale || this.showsReadout\n ? []\n : [\n {\n size: VesselImageSize.large,\n vesselImage: this.vesselImageSide,\n transform: `rotate(${this.pitch}deg)`,\n },\n {\n size: VesselImageSize.large,\n vesselImage: this.vesselImageFore,\n transform: `rotate(${this.roll}deg) scale(${this.normalizedScaleForeImage})`,\n },\n ]}\n .tickmarks=${tickmarks}\n .advices=${this.advices(pitchDeg, rollDeg)}\n ></obc-watch>\n `;\n }\n\n private advices(pitchDeg: number, rollDeg: number): AngleAdviceRaw[] {\n const advices: AngleAdviceRaw[] = [];\n const push = (\n center: number,\n halfDeg: number,\n max: number | undefined,\n trigger: boolean,\n cap: number\n ) => {\n if (max === undefined) return;\n const outer = Math.min(halfDeg, cap);\n const inner = Math.min(max, outer);\n const state = trigger ? AdviceState.triggered : AdviceState.regular;\n advices.push({\n minAngle: center - outer,\n maxAngle: center - inner,\n type: AdviceType.caution,\n state,\n hideMinTickmark: true,\n });\n advices.push({\n minAngle: center + inner,\n maxAngle: center + outer,\n type: AdviceType.caution,\n state,\n hideMaxTickmark: true,\n });\n };\n push(90, pitchDeg, this.maxPitchAdvice, this.triggerPitchAdvice, 30);\n push(180, rollDeg, this.maxRollAdvice, this.triggerRollAdvice, 45);\n if (this.isDualScale) {\n push(270, pitchDeg, this.maxPitchAdvice, this.triggerPitchAdvice, 30);\n push(0, rollDeg, this.maxRollAdvice, this.triggerRollAdvice, 45);\n }\n return advices;\n }\n\n static override styles = [\n centerReadoutStyles,\n css`\n * {\n box-sizing: border-box;\n }\n\n .container {\n position: relative;\n width: 100%;\n height: 100%;\n }\n\n .container > * {\n position: absolute;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n }\n\n .readout {\n display: flex;\n align-items: center;\n justify-content: center;\n }\n `,\n ];\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'obc-pitch-roll-heave': ObcPitchRollHeave;\n }\n}\n"],"names":["ObcPitchRollHeaveType","PitchRollHeavePriorityElement"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"pitch-roll-heave.js","sources":["../../../src/navigation-instruments/pitch-roll-heave/pitch-roll-heave.ts"],"sourcesContent":["import {LitElement, css, html, nothing, svg, type SVGTemplateResult} from 'lit';\nimport {property} from 'lit/decorators.js';\nimport '../watch/watch.js';\nimport {\n VesselImage,\n VesselImageSize,\n WatchCircleType,\n type WatchArea,\n OUTER_RING_RADIUS,\n innerRingRadiusFor,\n vesselImages,\n} from '../watch/watch.js';\nimport {arcTickmarks, TickmarkType, type Tickmark} from '../watch/tickmark.js';\nimport {AdviceState, AdviceType, type AngleAdviceRaw} from '../watch/advice.js';\nimport {customElement} from '../../decorator.js';\nimport {Priority} from '../types.js';\nimport {\n CenterReadoutArrangement,\n centerReadoutStyles,\n renderCenterReadouts,\n} from '../readout/center-readout.js';\nimport {ReadoutSize} from '../readout/readout.js';\nimport {\n computeZoomToFitArcFrame,\n normalizeArcAngle,\n shiftArcFrameToOuterEdge,\n} from '../../svghelpers/arc-frame.js';\nimport {\n linearTickInterval,\n watchfaceLinear,\n} from '../../building-blocks/instrument-linear/instrument-linear.js';\nimport type {\n LinearAdvice,\n LinearAdviceRaw,\n} from '../../building-blocks/instrument-linear/advice.js';\n\nexport enum ObcPitchRollHeaveType {\n /** Pitch on the right, roll at the bottom, heave in the left band slot. */\n singleScale = 'single-scale',\n /** Pitch and roll mirrored onto both sides, heave centred. */\n dualScale = 'dual-scale',\n}\n\nexport enum PitchRollHeavePriorityElement {\n pitch = 'pitch',\n roll = 'roll',\n heave = 'heave',\n}\n\n/** Half-side of the centre overlay viewBox in SVG units. */\nconst CENTRE_HALF = 200;\n\n/**\n * Minimum diagonal clearance, in central-layer pixels, between the zoomed\n * heave column and the adjacent roll band. Matches the constant\n * `obc-pitch-roll` uses between its own adjacent arcs.\n */\nconst CORNER_GAP_PX = 32;\n\n/** Numerical safety floor when an axis arc has to collapse for clearance. */\nconst MIN_ARC_HALF_DEG = 2;\n\n/** Width of the tick lane inside the heave column, in SVG units. */\nconst HEAVE_SCALE_WIDTH = 24;\n\n/** Band thickness at the natural, un-zoomed radii. */\nconst NOMINAL_BAND =\n OUTER_RING_RADIUS - innerRingRadiusFor(WatchCircleType.double);\n\n/**\n * Clearance kept between the centred (`dual-scale`) heave column's corners and\n * the surrounding band, in central-layer pixels. Sized so the un-zoomed\n * default is untouched — there the corner sits 13.2 units inside the free\n * radius — while the tighter zoomed layout is pulled back off the bands.\n */\nconst HEAVE_CENTRE_GAP_PX = 10;\n\n/**\n * The band slot the heave column fills, in central-layer coordinates.\n *\n * `outerR`/`innerR` bound the slot radially; `capRadius` is the radius of the\n * pitch arc's outer edge about its own origin, which is what the column's\n * height is measured against so the two line up. Un-zoomed the two radii\n * coincide; under zoom the arc is drawn on a shifted sub-watch and they differ.\n */\ninterface HeaveBand {\n outerR: number;\n innerR: number;\n capRadius: number;\n pitchDeg: number;\n}\n\n/**\n * Natural size of the heave column: as thick as the band slot, and tall enough\n * that its top and bottom edges sit level with the pitch arc's end caps.\n */\nfunction heaveColumnSize(band: HeaveBand): {width: number; height: number} {\n return {\n width: band.outerR - band.innerR,\n height: 2 * band.capRadius * Math.sin((band.pitchDeg * Math.PI) / 180),\n };\n}\n\n/**\n * Distance from a point to an axis-aligned rectangle; 0 when the point is\n * inside. Used to keep the zoomed roll band clear of the heave column, which\n * — unlike the arc-to-arc case — is a rectangle, so a corner may clear it on\n * one axis alone.\n */\nfunction distanceToRect(\n px: number,\n py: number,\n x0: number,\n y0: number,\n x1: number,\n y1: number\n): number {\n const dx = Math.max(0, x0 - px, px - x1);\n const dy = Math.max(0, y0 - py, py - y1);\n return Math.hypot(dx, dy);\n}\n\n/**\n * `<obc-pitch-roll-heave>` — Combined pitch, roll and heave indicator.\n *\n * Places a pitch arc, a roll arc and a linear heave column around one watch\n * face. The heave column occupies the same radial slot as the arcs, and its\n * height is derived from the pitch arc so its top and bottom edges sit level\n * with the pitch arc's end caps.\n *\n * Variants (`type`):\n * - `single-scale` (default) — pitch on the right, roll at the bottom, heave in\n * the left slot, vessel silhouettes in the centre.\n * - `dual-scale` — pitch and roll mirrored onto the opposite sides, with the\n * heave column moved to the centre.\n *\n * Set `hasReadout` to replace the centre content with stacked pitch, roll and\n * heave readouts, and `zoomToFitArc` to enlarge narrow arcs so they fill the\n * available space.\n *\n * @element obc-pitch-roll-heave\n * @experimental\n */\n@customElement('obc-pitch-roll-heave')\nexport class ObcPitchRollHeave extends LitElement {\n @property({type: String}) type: ObcPitchRollHeaveType =\n ObcPitchRollHeaveType.singleScale;\n\n @property({type: Number}) pitch = 0;\n @property({type: Number}) roll = 0;\n @property({type: Number}) heave = 0;\n @property({type: Number}) minAvgPitch = 0;\n @property({type: Number}) maxAvgPitch = 0;\n @property({type: Number}) minAvgRoll = 0;\n @property({type: Number}) maxAvgRoll = 0;\n @property({type: Number}) minTrendHeave = 0;\n @property({type: Number}) maxTrendHeave = 0;\n /** Half-extent of the heave scale in metres; the column spans `±heaveRange`. */\n @property({type: Number}) heaveRange = 10;\n\n /**\n * Half-extent of the pitch arc in degrees. Also drives the heave column\n * height, which is `2 · outerRadius · sin(pitchArcAngle)` so the column's\n * edges stay level with the pitch arc's end caps.\n */\n @property({type: Number}) pitchArcAngle = 30;\n /** Half-extent of the roll arc in degrees. */\n @property({type: Number}) rollArcAngle = 45;\n @property({type: Boolean}) zoomToFitArc = false;\n\n /**\n * Replaces the centre content with stacked pitch, roll and heave readouts.\n * Ignored when `type` is `dual-scale`, where the heave column occupies the\n * centre.\n * @availableWhen type==singleScale\n */\n @property({type: Boolean}) hasReadout = false;\n /** @availableWhen hasReadout==true */\n @property({type: String}) pitchLabel = 'Pitch';\n /** @availableWhen hasReadout==true */\n @property({type: String}) rollLabel = 'Roll';\n /** @availableWhen hasReadout==true */\n @property({type: String}) heaveLabel = 'Heave';\n /**\n * Unit shown in the pitch and roll readouts.\n * @availableWhen hasReadout==true\n */\n @property({type: String}) unit = 'DEG';\n /**\n * Unit shown in the heave readout.\n * @availableWhen hasReadout==true\n */\n @property({type: String}) heaveUnit = 'm';\n /** @availableWhen hasReadout==true */\n @property({type: Number}) fractionDigits = 0;\n\n /** @availableWhen type==singleScale && hasReadout==false */\n @property({type: String}) vesselImageFore: VesselImage = VesselImage.psvFore;\n /** @availableWhen type==singleScale && hasReadout==false */\n @property({type: String}) vesselImageSide: VesselImage = VesselImage.psvSide;\n /** @availableWhen type==singleScale && hasReadout==false */\n @property({type: Number}) scaleForeImage = 1;\n\n @property({type: Number}) maxPitchAdvice: number | undefined = undefined;\n @property({type: Number}) maxRollAdvice: number | undefined = undefined;\n /** @availableWhen maxPitchAdvice!=undefined */\n @property({type: Boolean}) triggerPitchAdvice = false;\n /** @availableWhen maxRollAdvice!=undefined */\n @property({type: Boolean}) triggerRollAdvice = false;\n @property({type: Array}) heaveAdvice: LinearAdvice[] = [];\n\n @property({type: String}) priority: Priority = Priority.regular;\n @property({type: Array, attribute: false})\n priorityElements: PitchRollHeavePriorityElement[] = [\n PitchRollHeavePriorityElement.pitch,\n PitchRollHeavePriorityElement.roll,\n PitchRollHeavePriorityElement.heave,\n ];\n\n private priorityFor(element: PitchRollHeavePriorityElement): Priority {\n const selected = Array.isArray(this.priorityElements)\n ? this.priorityElements\n : [];\n return selected.includes(element) ? this.priority : Priority.regular;\n }\n\n private needleColor(element: PitchRollHeavePriorityElement): string {\n return this.priorityFor(element) === Priority.enhanced\n ? 'var(--instrument-enhanced-secondary-color)'\n : 'var(--instrument-regular-secondary-color)';\n }\n\n private barColor(element: PitchRollHeavePriorityElement): string {\n return this.priorityFor(element) === Priority.enhanced\n ? 'var(--instrument-enhanced-tertiary-color)'\n : 'var(--instrument-regular-tertiary-color)';\n }\n\n private get normalizedScaleForeImage(): number {\n if (!Number.isFinite(this.scaleForeImage)) {\n return 1;\n }\n return Math.max(0, Math.min(2, this.scaleForeImage));\n }\n\n private get isDualScale(): boolean {\n return this.type === ObcPitchRollHeaveType.dualScale;\n }\n\n /** The centre readouts replace the vessels; never available in dual scale. */\n private get showsReadout(): boolean {\n return this.hasReadout && !this.isDualScale;\n }\n\n /**\n * Pitch half-extent, capped so a roll arc of the minimum size still fits in\n * the remaining quadrant.\n */\n private get requestedPitchArcAngle(): number {\n return Math.min(\n 90 - MIN_ARC_HALF_DEG,\n normalizeArcAngle(this.pitchArcAngle, 30)\n );\n }\n\n /**\n * Roll half-extent, clamped so the pitch and roll arcs cannot meet: the two\n * diagonal gaps each span `90 - pitch - roll` degrees, so the pair has to\n * stay under 90° combined.\n */\n private get requestedRollArcAngle(): number {\n const roll = normalizeArcAngle(this.rollArcAngle, 45);\n const headroom = 90 - this.requestedPitchArcAngle;\n return Math.max(MIN_ARC_HALF_DEG, Math.min(roll, headroom));\n }\n\n override render() {\n const pitchReq = this.requestedPitchArcAngle;\n const rollReq = this.requestedRollArcAngle;\n const overlayViewBox = `-${CENTRE_HALF} -${CENTRE_HALF} ${CENTRE_HALF * 2} ${CENTRE_HALF * 2}`;\n\n const layout = this.zoomToFitArc\n ? this.zoomLayout(pitchReq, rollReq)\n : undefined;\n const band: HeaveBand = layout?.band ?? {\n outerR: OUTER_RING_RADIUS,\n innerR: innerRingRadiusFor(WatchCircleType.double),\n capRadius: OUTER_RING_RADIUS,\n pitchDeg: pitchReq,\n };\n\n return html`\n <div class=\"container\">\n <svg viewBox=${overlayViewBox}>\n ${this.showsReadout ? nothing : this.renderCrosshair()}\n ${this.renderOverlayVessels()}\n ${this.zoomToFitArc || this.isDualScale\n ? nothing\n : this.renderComplement(pitchReq)}\n ${this.renderHeaveColumn(band)}\n </svg>\n ${layout\n ? this.renderZoomedArcs(layout)\n : this.renderFullWatch(pitchReq, rollReq)}\n ${this.showsReadout\n ? html`<div class=\"readout\">\n ${renderCenterReadouts(\n [\n {\n value: this.pitch,\n label: this.pitchLabel,\n unit: this.unit,\n fractionDigits: this.fractionDigits,\n size: ReadoutSize.large,\n priority: this.priorityFor(\n PitchRollHeavePriorityElement.pitch\n ),\n },\n {\n value: this.roll,\n label: this.rollLabel,\n unit: this.unit,\n fractionDigits: this.fractionDigits,\n size: ReadoutSize.large,\n priority: this.priorityFor(\n PitchRollHeavePriorityElement.roll\n ),\n },\n {\n value: this.heave,\n label: this.heaveLabel,\n unit: this.heaveUnit,\n fractionDigits: this.fractionDigits,\n size: ReadoutSize.large,\n priority: this.priorityFor(\n PitchRollHeavePriorityElement.heave\n ),\n },\n ],\n CenterReadoutArrangement.stacked\n )}\n </div>`\n : nothing}\n </div>\n `;\n }\n\n /**\n * Crosshair drawn on the overlay rather than through `obc-watch`'s own\n * `crosshairEnabled`: the design has the arc bands covering the arms, but\n * `obc-watch` renders its crosshair after the bands, i.e. on top of them.\n * Drawing it here puts it under the watch layer, so the bands and the heave\n * column mask it naturally.\n *\n * In `single-scale` nothing frames the segment above the vessel (the other\n * three arms end under the pitch band, roll band and heave column), so the\n * vertical arm stops at the centre instead of continuing upward. In\n * `dual-scale` the top roll band gives it a natural endpoint, so the full\n * arm is kept.\n */\n private renderCrosshair(): SVGTemplateResult {\n const r = OUTER_RING_RADIUS;\n const yTop = this.isDualScale ? -r : 0;\n return svg`\n <line\n x1=${-r} y1=\"0\" x2=${r} y2=\"0\"\n stroke=\"var(--instrument-frame-tertiary-color)\"\n vector-effect=\"non-scaling-stroke\"\n />\n <line\n x1=\"0\" y1=${yTop} x2=\"0\" y2=${r}\n stroke=\"var(--instrument-frame-tertiary-color)\"\n vector-effect=\"non-scaling-stroke\"\n />\n `;\n }\n\n /**\n * Vessel silhouettes on the centre layer. Only needed under zoom — the\n * un-zoomed path hands them to `obc-watch` via `vessels`, while the zoomed\n * sub-watches have no room for them.\n */\n private renderOverlayVessels(): SVGTemplateResult | typeof nothing {\n if (!this.zoomToFitArc || this.isDualScale || this.showsReadout) {\n return nothing;\n }\n const vesselScale = 224 / 160;\n return svg`\n <g style=\"transform: rotate(${this.pitch}deg) scale(${vesselScale}) translate(-80px, -80px);\">\n ${vesselImages[this.vesselImageSide]}\n </g>\n <g style=\"transform: rotate(${this.roll}deg) scale(${vesselScale * this.normalizedScaleForeImage}) translate(-80px, -80px);\">\n ${vesselImages[this.vesselImageFore]}\n </g>\n `;\n }\n\n /**\n * Thin ring bridging the empty span across the top, from where the heave\n * column's upper edge crosses the outer ring round to the pitch arc's start.\n * Because the column height is derived from the pitch arc, both ends land at\n * `±pitchArcAngle` off the vertical, making the ring symmetric. The two\n * diagonal gaps lower down are left open by design.\n */\n private renderComplement(pitchDeg: number): SVGTemplateResult {\n const r = OUTER_RING_RADIUS;\n const rad = (pitchDeg * Math.PI) / 180;\n // Ring runs clockwise from (270 + pitchDeg) through 0 to (90 - pitchDeg).\n const x1 = -r * Math.cos(rad);\n const y1 = -r * Math.sin(rad);\n const x2 = r * Math.cos(rad);\n const y2 = -r * Math.sin(rad);\n return svg`\n <path\n d=\"M ${x1} ${y1} A ${r} ${r} 0 0 1 ${x2} ${y2}\"\n fill=\"none\"\n stroke=\"var(--instrument-frame-tertiary-color)\"\n vector-effect=\"non-scaling-stroke\"\n />\n `;\n }\n\n /**\n * Linear heave scale, built from the same building block `obc-heave` uses.\n *\n * The column fills the band's radial slot, so its width equals the band\n * thickness and its height keeps its top and bottom edges level with the\n * pitch arc's end caps. In `single-scale` it sits in the left slot and is\n * mirrored so the tick lane faces outward; in `dual-scale` it moves to the\n * centre, unmirrored, and shrinks if the zoomed bands leave too little room.\n */\n private renderHeaveColumn(band: HeaveBand): SVGTemplateResult {\n const {width, height: naturalHeight} = heaveColumnSize(band);\n let height = naturalHeight;\n let offsetX = -(band.outerR + band.innerR) / 2;\n\n if (this.isDualScale) {\n offsetX = 0;\n // The centred column has to stay inside whatever the bands leave free.\n // Only the height gives way: the column's thickness reads as a match for\n // the band thickness, and shrinking both would break that.\n const free = band.innerR - HEAVE_CENTRE_GAP_PX;\n const halfWidth = width / 2;\n const maxHalfHeight =\n free > halfWidth ? Math.sqrt(free * free - halfWidth * halfWidth) : 0;\n height = Math.min(height, 2 * maxHalfHeight);\n }\n\n const scaleWidth = HEAVE_SCALE_WIDTH * Math.min(1, width / NOMINAL_BAND);\n\n const gauge = watchfaceLinear(\n {\n height,\n width,\n scaleWidth,\n minValue: -this.heaveRange,\n maxValue: this.heaveRange,\n },\n [{min: this.minTrendHeave, max: this.maxTrendHeave}],\n {value: this.heave},\n {container: 'var(--instrument-frame-primary-color)'},\n {\n hideContainer: false,\n off: false,\n priority: this.priorityFor(PitchRollHeavePriorityElement.heave),\n },\n {\n mainTickmarks: [],\n primaryTickmarkInterval: 0,\n secondaryTickmarkInterval: linearTickInterval(height, this.heaveRange),\n },\n this.heaveAdvices\n );\n\n const mirror = this.isDualScale ? '' : ' scale(-1, 1)';\n return svg`<g transform=\"translate(${offsetX}, 0)${mirror}\">${gauge}</g>`;\n }\n\n private get heaveAdvices(): LinearAdviceRaw[] {\n return this.heaveAdvice.map((advice) => {\n const isActive =\n this.maxTrendHeave >= advice.min && this.minTrendHeave <= advice.max;\n const state = isActive\n ? AdviceState.triggered\n : advice.hinted\n ? AdviceState.hinted\n : AdviceState.regular;\n return {...advice, state} satisfies LinearAdviceRaw;\n });\n }\n\n /**\n * Zoom-fit geometry, computed once per render and shared by the arc layer\n * and the heave column.\n *\n * Frames are built at the REQUESTED half-extents with the same math as\n * `obc-pitch` / `obc-roll`, so each sub-watch matches its standalone\n * equivalent. Two clearance passes then shorten only the *rendered* arcs —\n * the frames stay untouched, so band thickness, position and zoom level are\n * preserved:\n *\n * 1. pitch vs roll at the diagonal, ratio-preserving, exactly as\n * `obc-pitch-roll` does it;\n * 2. roll vs the heave column, `single-scale` only, shortening the roll arc\n * alone. Because the column's height follows the pitch arc, pass 1 already\n * pulls the column in whenever pitch shrinks, so pitch needs no second\n * pass.\n */\n private zoomLayout(pitchReq: number, rollReq: number) {\n const ext = 48;\n const targetSize = (176 + ext) * 2;\n const innerNat = innerRingRadiusFor(WatchCircleType.double);\n const buildFrame = (halfDeg: number) => {\n const areas: WatchArea[] = [\n {\n startAngle: -halfDeg,\n endAngle: halfDeg,\n roundOutsideCut: true,\n roundInsideCut: true,\n },\n ];\n const baseFrame = computeZoomToFitArcFrame({\n areas,\n outerRadius: OUTER_RING_RADIUS,\n innerRadius: innerNat,\n extension: ext,\n targetSize,\n });\n const subArcFrame = shiftArcFrameToOuterEdge(\n baseFrame,\n OUTER_RING_RADIUS + baseFrame.radiusOffset,\n OUTER_RING_RADIUS,\n CENTRE_HALF\n );\n const scale = (CENTRE_HALF * 2) / subArcFrame.width;\n const outerR = (OUTER_RING_RADIUS + baseFrame.radiusOffset) * scale;\n const innerR = (innerNat + baseFrame.radiusOffset) * scale;\n return {subArcFrame, outerR, innerR};\n };\n const pitchFrame = buildFrame(pitchReq);\n const rollFrame = buildFrame(rollReq);\n\n const OR = OUTER_RING_RADIUS;\n const toRad = (deg: number) => (deg * Math.PI) / 180;\n const signedDist = (\n px: number,\n py: number,\n qx: number,\n qy: number\n ): number => {\n const dx = qx - px;\n const dy = qy - py;\n const mag = Math.hypot(dx, dy);\n return dx > 0 && dy > 0 ? mag : -mag;\n };\n // Diagonal gap between two adjacent cardinal bands. All such gaps in this\n // layout are congruent, so one pair stands in for the rest.\n const minGap = (apRad: number, arRad: number): number => {\n const cosP = Math.cos(apRad);\n const sinP = Math.sin(apRad);\n const cosR = Math.cos(arRad);\n const sinR = Math.sin(arRad);\n const p1x = pitchFrame.innerR * sinP;\n const p1y = pitchFrame.outerR - OR - pitchFrame.innerR * cosP;\n const p2x = pitchFrame.outerR * sinP;\n const p2y = pitchFrame.outerR - OR - pitchFrame.outerR * cosP;\n const q1x = OR - rollFrame.outerR + rollFrame.innerR * cosR;\n const q1y = -rollFrame.innerR * sinR;\n const q2x = OR - rollFrame.outerR + rollFrame.outerR * cosR;\n const q2y = -rollFrame.outerR * sinR;\n return Math.min(\n signedDist(p1x, p1y, q1x, q1y),\n signedDist(p2x, p2y, q2x, q2y)\n );\n };\n\n let aP = toRad(pitchReq);\n let aR = toRad(rollReq);\n if (minGap(aP, aR) < CORNER_GAP_PX) {\n let lo = 0;\n let hi = 1;\n for (let i = 0; i < 40; i++) {\n const mid = (lo + hi) / 2;\n if (minGap(aP * mid, aR * mid) >= CORNER_GAP_PX) {\n lo = mid;\n } else {\n hi = mid;\n }\n }\n aP *= lo;\n aR *= lo;\n }\n const pitchClampedDeg = Math.max(MIN_ARC_HALF_DEG, (aP * 180) / Math.PI);\n let rollClampedDeg = Math.max(MIN_ARC_HALF_DEG, (aR * 180) / Math.PI);\n\n const bandFor = (pitchDeg: number): HeaveBand => ({\n outerR: OR,\n innerR: OR - (pitchFrame.outerR - pitchFrame.innerR),\n capRadius: pitchFrame.outerR,\n pitchDeg,\n });\n\n if (!this.isDualScale) {\n // Roll's left end caps versus the heave column rectangle. Shrinking the\n // roll arc moves both caps toward the bottom cardinal, away from the\n // column, so the gap grows monotonically as the scalar shrinks.\n const band = bandFor(pitchClampedDeg);\n const {width, height} = heaveColumnSize(band);\n const x1 = -band.innerR;\n const x0 = x1 - width;\n const y1 = height / 2;\n const heaveGap = (arRad: number): number => {\n const cosR = Math.cos(arRad);\n const sinR = Math.sin(arRad);\n const outerX = -rollFrame.outerR * sinR;\n const outerY = OR - rollFrame.outerR + rollFrame.outerR * cosR;\n const innerX = -rollFrame.innerR * sinR;\n const innerY = OR - rollFrame.outerR + rollFrame.innerR * cosR;\n return Math.min(\n distanceToRect(outerX, outerY, x0, -y1, x1, y1),\n distanceToRect(innerX, innerY, x0, -y1, x1, y1)\n );\n };\n if (heaveGap(toRad(rollClampedDeg)) < CORNER_GAP_PX) {\n let lo = 0;\n let hi = rollClampedDeg;\n for (let i = 0; i < 40; i++) {\n const mid = (lo + hi) / 2;\n if (heaveGap(toRad(mid)) >= CORNER_GAP_PX) {\n lo = mid;\n } else {\n hi = mid;\n }\n }\n rollClampedDeg = Math.max(MIN_ARC_HALF_DEG, lo);\n }\n }\n\n return {\n pitchFrame,\n rollFrame,\n pitchClampedDeg,\n rollClampedDeg,\n band: bandFor(pitchClampedDeg),\n };\n }\n\n /**\n * Zoomed-arc layer: CSS-rotated `<obc-watch>` instances, each holding a\n * single arc rendered at the watch's natural top and rotated onto its\n * cardinal. `single-scale` places pitch right and roll bottom; `dual-scale`\n * mirrors both. The heave column lives on the centre overlay.\n */\n private renderZoomedArcs(layout: ReturnType<typeof this.zoomLayout>) {\n const {pitchFrame, rollFrame, pitchClampedDeg, rollClampedDeg} = layout;\n\n const subAreas = (halfDeg: number): WatchArea[] => [\n {\n startAngle: -halfDeg,\n endAngle: halfDeg,\n roundOutsideCut: true,\n roundInsideCut: true,\n },\n ];\n\n // Clip each sub-watch to the sector its (possibly shortened) arc covers so\n // the indicator cannot leak past the visible band.\n const sectorClip = (\n halfDeg: number,\n frame: typeof rollFrame.subArcFrame\n ): string => {\n const oxPct = (-frame.x / frame.width) * 100;\n const oyPct = (-frame.y / frame.height) * 100;\n const dxPct = oyPct * Math.tan((halfDeg * Math.PI) / 180);\n const lx = Math.max(0, oxPct - dxPct);\n const rx = Math.min(100, oxPct + dxPct);\n return `polygon(${oxPct}% ${oyPct}%, ${lx}% 0%, ${rx}% 0%)`;\n };\n\n const axis = (\n element: PitchRollHeavePriorityElement,\n frame: typeof rollFrame,\n halfDeg: number,\n value: number,\n avgMin: number,\n avgMax: number,\n max: number | undefined,\n trigger: boolean,\n cap: number\n ) => ({\n arcFrame: frame.subArcFrame,\n areas: subAreas(halfDeg),\n barAreas: [\n {\n startAngle: avgMin,\n endAngle: avgMax,\n fillColor: this.barColor(element),\n },\n ],\n needles: [\n {\n angle: value,\n fillColor: this.needleColor(element),\n strokeColor: 'var(--border-silhouette-color)',\n },\n ],\n advices: this.subAdvices(halfDeg, max, trigger, cap),\n tickmarks: [\n {angle: 0, type: TickmarkType.main},\n ...arcTickmarks(0, halfDeg),\n ],\n clipPath: sectorClip(halfDeg, frame.subArcFrame),\n });\n\n const pitchAxis = axis(\n PitchRollHeavePriorityElement.pitch,\n pitchFrame,\n pitchClampedDeg,\n this.pitch,\n this.minAvgPitch,\n this.maxAvgPitch,\n this.maxPitchAdvice,\n this.triggerPitchAdvice,\n 30\n );\n const rollAxis = axis(\n PitchRollHeavePriorityElement.roll,\n rollFrame,\n rollClampedDeg,\n this.roll,\n this.minAvgRoll,\n this.maxAvgRoll,\n this.maxRollAdvice,\n this.triggerRollAdvice,\n 45\n );\n\n const subWatch = (rotation: number, a: typeof pitchAxis) => html`\n <obc-watch\n class=\"sub-watch\"\n style=\"transform: rotate(${rotation}deg); clip-path: ${a.clipPath};\"\n .watchCircleType=${WatchCircleType.double}\n .zoomToFitArc=${true}\n .arcFrame=${a.arcFrame}\n .areas=${a.areas}\n .barAreas=${a.barAreas}\n .needles=${a.needles}\n .vessels=${[]}\n .tickmarks=${a.tickmarks}\n .advices=${a.advices}\n ></obc-watch>\n `;\n\n return html`\n ${subWatch(90, pitchAxis)} ${subWatch(180, rollAxis)}\n ${this.isDualScale\n ? html`${subWatch(270, pitchAxis)} ${subWatch(0, rollAxis)}`\n : nothing}\n `;\n }\n\n /** Caution bands for one sub-watch axis, at sub-watch-local angles. */\n private subAdvices(\n halfDeg: number,\n max: number | undefined,\n trigger: boolean,\n cap: number\n ): AngleAdviceRaw[] {\n if (max === undefined) return [];\n const outer = Math.min(halfDeg, cap);\n const inner = Math.min(max, outer);\n const state = trigger ? AdviceState.triggered : AdviceState.regular;\n return [\n {\n minAngle: -outer,\n maxAngle: -inner,\n type: AdviceType.caution,\n state,\n hideMinTickmark: true,\n },\n {\n minAngle: inner,\n maxAngle: outer,\n type: AdviceType.caution,\n state,\n hideMaxTickmark: true,\n },\n ];\n }\n\n /** Areas, tickmarks, bars and needles for the un-zoomed single watch. */\n private renderFullWatch(pitchDeg: number, rollDeg: number) {\n const arc = (center: number, half: number): WatchArea => ({\n startAngle: center - half,\n endAngle: center + half,\n roundOutsideCut: true,\n roundInsideCut: true,\n });\n\n const areas: WatchArea[] = [arc(90, pitchDeg), arc(180, rollDeg)];\n const tickmarks: Tickmark[] = [\n {angle: 90, type: TickmarkType.main},\n {angle: 180, type: TickmarkType.main},\n ...arcTickmarks(90, pitchDeg),\n ...arcTickmarks(180, rollDeg),\n ];\n const barAreas = [\n {\n startAngle: 90 + this.minAvgPitch,\n endAngle: 90 + this.maxAvgPitch,\n fillColor: this.barColor(PitchRollHeavePriorityElement.pitch),\n },\n {\n startAngle: 180 + this.minAvgRoll,\n endAngle: 180 + this.maxAvgRoll,\n fillColor: this.barColor(PitchRollHeavePriorityElement.roll),\n },\n ];\n const needles = [\n {\n angle: 90 + this.pitch,\n fillColor: this.needleColor(PitchRollHeavePriorityElement.pitch),\n strokeColor: 'var(--border-silhouette-color)',\n },\n {\n angle: 180 + this.roll,\n fillColor: this.needleColor(PitchRollHeavePriorityElement.roll),\n strokeColor: 'var(--border-silhouette-color)',\n },\n ];\n\n if (this.isDualScale) {\n areas.push(arc(270, pitchDeg), arc(0, rollDeg));\n tickmarks.push(\n {angle: 270, type: TickmarkType.main},\n {angle: 0, type: TickmarkType.main},\n ...arcTickmarks(270, pitchDeg),\n ...arcTickmarks(0, rollDeg)\n );\n barAreas.push(\n {\n startAngle: 270 + this.minAvgPitch,\n endAngle: 270 + this.maxAvgPitch,\n fillColor: this.barColor(PitchRollHeavePriorityElement.pitch),\n },\n {\n startAngle: this.minAvgRoll,\n endAngle: this.maxAvgRoll,\n fillColor: this.barColor(PitchRollHeavePriorityElement.roll),\n }\n );\n needles.push(\n {\n angle: 270 + this.pitch,\n fillColor: this.needleColor(PitchRollHeavePriorityElement.pitch),\n strokeColor: 'var(--border-silhouette-color)',\n },\n {\n angle: this.roll,\n fillColor: this.needleColor(PitchRollHeavePriorityElement.roll),\n strokeColor: 'var(--border-silhouette-color)',\n }\n );\n }\n\n return html`\n <obc-watch\n .watchCircleType=${WatchCircleType.double}\n .zoomToFitArc=${false}\n .areas=${areas}\n .barAreas=${barAreas}\n .needles=${needles}\n .vessels=${this.isDualScale || this.showsReadout\n ? []\n : [\n {\n size: VesselImageSize.large,\n vesselImage: this.vesselImageSide,\n transform: `rotate(${this.pitch}deg)`,\n },\n {\n size: VesselImageSize.large,\n vesselImage: this.vesselImageFore,\n transform: `rotate(${this.roll}deg) scale(${this.normalizedScaleForeImage})`,\n },\n ]}\n .tickmarks=${tickmarks}\n .advices=${this.advices(pitchDeg, rollDeg)}\n ></obc-watch>\n `;\n }\n\n private advices(pitchDeg: number, rollDeg: number): AngleAdviceRaw[] {\n const advices: AngleAdviceRaw[] = [];\n const push = (\n center: number,\n halfDeg: number,\n max: number | undefined,\n trigger: boolean,\n cap: number\n ) => {\n if (max === undefined) return;\n const outer = Math.min(halfDeg, cap);\n const inner = Math.min(max, outer);\n const state = trigger ? AdviceState.triggered : AdviceState.regular;\n advices.push({\n minAngle: center - outer,\n maxAngle: center - inner,\n type: AdviceType.caution,\n state,\n hideMinTickmark: true,\n });\n advices.push({\n minAngle: center + inner,\n maxAngle: center + outer,\n type: AdviceType.caution,\n state,\n hideMaxTickmark: true,\n });\n };\n push(90, pitchDeg, this.maxPitchAdvice, this.triggerPitchAdvice, 30);\n push(180, rollDeg, this.maxRollAdvice, this.triggerRollAdvice, 45);\n if (this.isDualScale) {\n push(270, pitchDeg, this.maxPitchAdvice, this.triggerPitchAdvice, 30);\n push(0, rollDeg, this.maxRollAdvice, this.triggerRollAdvice, 45);\n }\n return advices;\n }\n\n static override styles = [\n centerReadoutStyles,\n css`\n * {\n box-sizing: border-box;\n }\n\n .container {\n position: relative;\n width: 100%;\n height: 100%;\n }\n\n .container > * {\n position: absolute;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n }\n\n .readout {\n display: flex;\n align-items: center;\n justify-content: center;\n }\n `,\n ];\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'obc-pitch-roll-heave': ObcPitchRollHeave;\n }\n}\n"],"names":["ObcPitchRollHeaveType","PitchRollHeavePriorityElement"],"mappings":"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"}
|
|
@@ -23,7 +23,8 @@ export { RotType, RotPosition };
|
|
|
23
23
|
* - **Track bar** (`hasTrackBar`): A bar in the ring band growing from the
|
|
24
24
|
* twelve o'clock position to the measured rate of turn, with a needle
|
|
25
25
|
* marker at its end and sector tickmarks (pairs with
|
|
26
|
-
* `watchCircleType="double"` for the banded face
|
|
26
|
+
* `watchCircleType="double"` for the banded face, or `"triple"` when the
|
|
27
|
+
* ROT dots sit on the inner circle).
|
|
27
28
|
* - **Center readout** (`hasReadout`): A centered readout showing the
|
|
28
29
|
* measured rate of turn (label `ROT`, unit `DEG/min` by default).
|
|
29
30
|
* - **Color priority**: Uses `priority` to select regular or enhanced color
|
|
@@ -74,7 +75,9 @@ export declare class ObcRateOfTurn extends LitElement {
|
|
|
74
75
|
* When `true`, shows a bar in the ring band from the twelve o'clock
|
|
75
76
|
* position to the measured rate of turn, with a needle marker at its end
|
|
76
77
|
* and sector tickmarks. Pairs with `watchCircleType="double"` for the
|
|
77
|
-
* banded face
|
|
78
|
+
* banded face — or `"triple"` when `rotPosition` is `innerCircle`, so the
|
|
79
|
+
* dots get their inner track too. Driven by `rateOfTurnDegreesPerMinute`
|
|
80
|
+
* only.
|
|
78
81
|
*/
|
|
79
82
|
hasTrackBar: boolean;
|
|
80
83
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rate-of-turn.d.ts","sourceRoot":"","sources":["../../../src/navigation-instruments/rate-of-turn/rate-of-turn.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,UAAU,EAAgC,MAAM,KAAK,CAAC;AAE9D,OAAO,mBAAmB,CAAC;AAC3B,OAAO,EAAC,eAAe,EAAE,OAAO,EAAE,WAAW,EAAC,MAAM,mBAAmB,CAAC;AAUxE,OAAO,EAAC,QAAQ,EAAC,MAAM,aAAa,CAAC;AAErC,OAAO,EAAC,OAAO,EAAE,WAAW,EAAC,CAAC;AAE9B
|
|
1
|
+
{"version":3,"file":"rate-of-turn.d.ts","sourceRoot":"","sources":["../../../src/navigation-instruments/rate-of-turn/rate-of-turn.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,UAAU,EAAgC,MAAM,KAAK,CAAC;AAE9D,OAAO,mBAAmB,CAAC;AAC3B,OAAO,EAAC,eAAe,EAAE,OAAO,EAAE,WAAW,EAAC,MAAM,mBAAmB,CAAC;AAUxE,OAAO,EAAC,QAAQ,EAAC,MAAM,aAAa,CAAC;AAErC,OAAO,EAAC,OAAO,EAAE,WAAW,EAAC,CAAC;AAE9B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0CG;AACH,qBACa,aAAc,SAAQ,UAAU;IAC3C;;;OAGG;IACuB,0BAA0B,EAAE,MAAM,GAAG,SAAS,CAAC;IAEzE;;;OAGG;IACuB,qBAAqB,EAAE,MAAM,CAAM;IAE7D;;;;OAIG;IACuB,kBAAkB,EAAE,MAAM,CAAK;IAE/B,OAAO,EAAE,OAAO,CAAgB;IAChC,WAAW,EAAE,WAAW,CAAqB;IAC7C,QAAQ,EAAE,QAAQ,CAAoB;IACtC,aAAa,EAAE,MAAM,CAAK;IAC1B,WAAW,EAAE,MAAM,CAAM;IACzB,eAAe,EAAE,eAAe,CACjC;IACE,gBAAgB,EAAE,OAAO,CAAS;IACnC,iBAAiB,EAAE,MAAM,CAAyB;IAC5E;;;;;;;OAOG;IACwB,WAAW,EAAE,OAAO,CAAS;IACxD;;;;;OAKG;IACuB,WAAW,EAAE,MAAM,CAAM;IACnD;;;OAGG;IACuB,YAAY,EAAE,MAAM,CAAM;IACpD;;;OAGG;IACwB,UAAU,EAAE,OAAO,CAAS;IACvD;;;OAGG;IACuB,KAAK,SAAS;IACxC;;;OAGG;IACuB,IAAI,SAAa;IAC3C;;;OAGG;IACuB,cAAc,SAAK;IAE7C,OAAO,KAAK,aAAa,GAKxB;IAED,OAAO,KAAK,aAAa,GAaxB;IAED,OAAO,KAAK,gBAAgB,GAc3B;IAED,OAAO,KAAK,cAAc,GAOzB;IAED,OAAgB,MAAM,4BA6BpB;IAEO,MAAM;CAoDhB;AAED,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,kBAAkB,EAAE,aAAa,CAAC;KACnC;CACF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rate-of-turn.js","sources":["../../../src/navigation-instruments/rate-of-turn/rate-of-turn.ts"],"sourcesContent":["import {LitElement, css, html, nothing, unsafeCSS} from 'lit';\nimport {property} from 'lit/decorators.js';\nimport '../watch/watch.js';\nimport {WatchCircleType, RotType, RotPosition} from '../watch/watch.js';\nimport {Tickmark, TickmarkType} from '../watch/tickmark.js';\nimport {\n centerReadoutStyles,\n renderCenterReadouts,\n} from '../readout/center-readout.js';\nimport {ReadoutSize} from '../readout/readout.js';\nimport instrumentReadoutStyle from '../readout/instrument-readout.css?inline';\nimport {ROT_ZERO_DEADBAND_DEG} from './rot-renderer.js';\nimport {customElement} from '../../decorator.js';\nimport {Priority} from '../types.js';\n\nexport {RotType, RotPosition};\n\n/**\n * `<obc-rate-of-turn>` — Standalone rate-of-turn indicator rendered on a circular watch face.\n *\n * Wraps `<obc-watch>` to display a spinning-dot or arc-bar ROT visualization\n * without any additional instrument overlays. Useful for isolating the ROT\n * indicator in layouts where heading/compass elements are handled separately.\n *\n * ## Features\n *\n * - **Dot mode** (`rotType=\"dots\"`): Five evenly-spaced dots spin at the\n * resolved rotations-per-minute (derived from\n * `rateOfTurnDegreesPerMinute × rotDotAnimationFactor / 360`).\n * - **Bar mode** (`rotType=\"bar\"`): A banana-shaped arc from `barStartAngle`\n * to `barEndAngle` with clipped spinning dots inside.\n * - **Track position**: Place the indicator on the outer scale ring\n * (`rotPosition=\"scale\"`) or the inner circle\n * (`rotPosition=\"innerCircle\"`).\n * - **Track bar** (`hasTrackBar`): A bar in the ring band growing from the\n * twelve o'clock position to the measured rate of turn, with a needle\n * marker at its end and sector tickmarks (pairs with\n * `watchCircleType=\"double\"` for the banded face).\n * - **Center readout** (`hasReadout`): A centered readout showing the\n * measured rate of turn (label `ROT`, unit `DEG/min` by default).\n * - **Color priority**: Uses `priority` to select regular or enhanced color\n * palette; `rotPortStarboard` colors the track bar and needle by turn\n * direction.\n *\n * ## Usage Guidelines\n *\n * - Set `rateOfTurnDegreesPerMinute` to the current sensor value in degrees\n * per minute (the maritime/AIS convention). Sign controls direction\n * (positive = starboard / clockwise).\n * - Tune `rotDotAnimationFactor` to amplify the dot animation independently\n * of the physical value (default `18` ≈ 1 rpm at 20°/min).\n * - In bar mode, `barStartAngle` and `barEndAngle` define the static arc\n * span (0° = 12 o'clock, clockwise).\n * - Change `watchCircleType` to match the surrounding instrument ring style\n * (e.g. `triple` for compass contexts).\n *\n * @element obc-rate-of-turn\n * @stable\n */\n@customElement('obc-rate-of-turn')\nexport class ObcRateOfTurn extends LitElement {\n /**\n * Measured rate of turn in degrees per minute (positive = starboard).\n * When `undefined`, the legacy `rotationsPerMinute` value is used.\n */\n @property({type: Number}) rateOfTurnDegreesPerMinute: number | undefined;\n\n /**\n * Visual amplification applied to the spinning dot animation. Default `18`\n * keeps the legacy visual feel (≈1 rpm at 20°/min).\n */\n @property({type: Number}) rotDotAnimationFactor: number = 18;\n\n /**\n * @deprecated Use `rateOfTurnDegreesPerMinute` (and optionally\n * `rotDotAnimationFactor`) instead. Takes effect only when\n * `rateOfTurnDegreesPerMinute` is `undefined`.\n */\n @property({type: Number}) rotationsPerMinute: number = 1;\n\n @property({type: String}) rotType: RotType = RotType.dots;\n @property({type: String}) rotPosition: RotPosition = RotPosition.scale;\n @property({type: String}) priority: Priority = Priority.regular;\n @property({type: Number}) barStartAngle: number = 0;\n @property({type: Number}) barEndAngle: number = 30;\n @property({type: String}) watchCircleType: WatchCircleType =\n WatchCircleType.single;\n @property({type: Boolean}) rotPortStarboard: boolean = false;\n @property({type: Number}) rotAtZeroDeadband: number = ROT_ZERO_DEADBAND_DEG;\n /**\n * When `true`, shows a bar in the ring band from the twelve o'clock\n * position to the measured rate of turn, with a needle marker at its end\n * and sector tickmarks. Pairs with `watchCircleType=\"double\"` for the\n * banded face. Driven by `rateOfTurnDegreesPerMinute` only.\n */\n @property({type: Boolean}) hasTrackBar: boolean = false;\n /**\n * Bar-extent reference value in **degrees per minute**: the track bar\n * reaches ±`rotArcExtent` when the measured ROT equals ±`rotMaxValue`.\n * Default `60` aligns with ES-TRIN 2025/1 Art. 3.02.\n * @availableWhen hasTrackBar==true\n */\n @property({type: Number}) rotMaxValue: number = 60;\n /**\n * Arc extent of the track bar in degrees per direction. Default `60`.\n * @availableWhen hasTrackBar==true\n */\n @property({type: Number}) rotArcExtent: number = 60;\n /**\n * When `true`, shows a centered `<obc-readout>` with the measured rate of\n * turn. Shows a dash while `rateOfTurnDegreesPerMinute` is unset.\n */\n @property({type: Boolean}) hasReadout: boolean = false;\n /**\n * Readout label. Default `ROT`.\n * @availableWhen hasReadout==true\n */\n @property({type: String}) label = 'ROT';\n /**\n * Readout unit. Default `DEG/min`.\n * @availableWhen hasReadout==true\n */\n @property({type: String}) unit = 'DEG/min';\n /**\n * Number of fraction digits shown in the readout. Default `0`.\n * @availableWhen hasReadout==true\n */\n @property({type: Number}) fractionDigits = 0;\n\n private get trackBarAngle(): number {\n const max = this.rotMaxValue || 1;\n const rot = this.rateOfTurnDegreesPerMinute ?? 0;\n const ratio = Math.max(-1, Math.min(1, rot / max));\n return ratio * this.rotArcExtent;\n }\n\n private get trackBarColor(): string {\n if (this.rotPortStarboard) {\n const rot = this.rateOfTurnDegreesPerMinute ?? 0;\n if (rot > 0) {\n return 'var(--instrument-starboard-secondary-color)';\n }\n if (rot < 0) {\n return 'var(--instrument-port-secondary-color)';\n }\n }\n return this.priority === Priority.enhanced\n ? 'var(--instrument-enhanced-tertiary-color)'\n : 'var(--instrument-regular-tertiary-color)';\n }\n\n private get trackNeedleColor(): string {\n if (this.rotPortStarboard) {\n const rot = this.rateOfTurnDegreesPerMinute ?? 0;\n if (rot > 0) {\n return 'var(--instrument-starboard-primary-color)';\n }\n if (rot < 0) {\n return 'var(--instrument-port-primary-color)';\n }\n return 'var(--instrument-regular-secondary-color)';\n }\n return this.priority === Priority.enhanced\n ? 'var(--instrument-enhanced-secondary-color)'\n : 'var(--instrument-regular-secondary-color)';\n }\n\n private get trackTickmarks(): Tickmark[] {\n const ticks: Tickmark[] = [{angle: 0, type: TickmarkType.main}];\n for (let angle = 30; angle <= this.rotArcExtent; angle += 30) {\n ticks.push({angle, type: TickmarkType.primary});\n ticks.push({angle: -angle, type: TickmarkType.primary});\n }\n return ticks;\n }\n\n static override styles = [\n unsafeCSS(instrumentReadoutStyle),\n centerReadoutStyles,\n css`\n * {\n box-sizing: border-box;\n }\n\n .container {\n position: relative;\n width: 100%;\n height: 100%;\n }\n\n .container > * {\n position: absolute;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n }\n\n .center-readout-overlay {\n display: flex;\n align-items: center;\n justify-content: center;\n pointer-events: none;\n }\n `,\n ];\n\n override render() {\n return html`<div class=\"container\">\n <obc-watch\n .watchCircleType=${this.watchCircleType}\n .priority=${this.priority}\n .tickmarks=${this.hasTrackBar ? this.trackTickmarks : []}\n .barAreas=${this.hasTrackBar\n ? [\n {\n startAngle: 0,\n endAngle: this.trackBarAngle,\n fillColor: this.trackBarColor,\n },\n ]\n : []}\n .needles=${this.hasTrackBar\n ? [\n {\n angle: this.trackBarAngle,\n fillColor: this.trackNeedleColor,\n strokeColor: 'var(--border-silhouette-color)',\n },\n ]\n : []}\n .rotType=${this.rotType}\n .rotPosition=${this.rotPosition}\n .rotStartAngle=${this.barStartAngle}\n .rotEndAngle=${this.barEndAngle}\n .rateOfTurnDegreesPerMinute=${this.rateOfTurnDegreesPerMinute}\n .rotDotAnimationFactor=${this.rotDotAnimationFactor}\n .rotationsPerMinute=${this.rotationsPerMinute}\n .rotPortStarboard=${this.rotPortStarboard}\n .rotAtZeroDeadband=${this.rotAtZeroDeadband}\n ></obc-watch>\n ${this.hasReadout\n ? html`<div class=\"center-readout-overlay\">\n ${renderCenterReadouts([\n {\n value: this.rateOfTurnDegreesPerMinute ?? null,\n label: this.label,\n unit: this.unit,\n fractionDigits: this.fractionDigits,\n size: ReadoutSize.large,\n priority: this.priority,\n centerValue: true,\n centerMeta: true,\n },\n ])}\n </div>`\n : nothing}\n </div>`;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'obc-rate-of-turn': ObcRateOfTurn;\n }\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"rate-of-turn.js","sources":["../../../src/navigation-instruments/rate-of-turn/rate-of-turn.ts"],"sourcesContent":["import {LitElement, css, html, nothing, unsafeCSS} from 'lit';\nimport {property} from 'lit/decorators.js';\nimport '../watch/watch.js';\nimport {WatchCircleType, RotType, RotPosition} from '../watch/watch.js';\nimport {Tickmark, TickmarkType} from '../watch/tickmark.js';\nimport {\n centerReadoutStyles,\n renderCenterReadouts,\n} from '../readout/center-readout.js';\nimport {ReadoutSize} from '../readout/readout.js';\nimport instrumentReadoutStyle from '../readout/instrument-readout.css?inline';\nimport {ROT_ZERO_DEADBAND_DEG} from './rot-renderer.js';\nimport {customElement} from '../../decorator.js';\nimport {Priority} from '../types.js';\n\nexport {RotType, RotPosition};\n\n/**\n * `<obc-rate-of-turn>` — Standalone rate-of-turn indicator rendered on a circular watch face.\n *\n * Wraps `<obc-watch>` to display a spinning-dot or arc-bar ROT visualization\n * without any additional instrument overlays. Useful for isolating the ROT\n * indicator in layouts where heading/compass elements are handled separately.\n *\n * ## Features\n *\n * - **Dot mode** (`rotType=\"dots\"`): Five evenly-spaced dots spin at the\n * resolved rotations-per-minute (derived from\n * `rateOfTurnDegreesPerMinute × rotDotAnimationFactor / 360`).\n * - **Bar mode** (`rotType=\"bar\"`): A banana-shaped arc from `barStartAngle`\n * to `barEndAngle` with clipped spinning dots inside.\n * - **Track position**: Place the indicator on the outer scale ring\n * (`rotPosition=\"scale\"`) or the inner circle\n * (`rotPosition=\"innerCircle\"`).\n * - **Track bar** (`hasTrackBar`): A bar in the ring band growing from the\n * twelve o'clock position to the measured rate of turn, with a needle\n * marker at its end and sector tickmarks (pairs with\n * `watchCircleType=\"double\"` for the banded face, or `\"triple\"` when the\n * ROT dots sit on the inner circle).\n * - **Center readout** (`hasReadout`): A centered readout showing the\n * measured rate of turn (label `ROT`, unit `DEG/min` by default).\n * - **Color priority**: Uses `priority` to select regular or enhanced color\n * palette; `rotPortStarboard` colors the track bar and needle by turn\n * direction.\n *\n * ## Usage Guidelines\n *\n * - Set `rateOfTurnDegreesPerMinute` to the current sensor value in degrees\n * per minute (the maritime/AIS convention). Sign controls direction\n * (positive = starboard / clockwise).\n * - Tune `rotDotAnimationFactor` to amplify the dot animation independently\n * of the physical value (default `18` ≈ 1 rpm at 20°/min).\n * - In bar mode, `barStartAngle` and `barEndAngle` define the static arc\n * span (0° = 12 o'clock, clockwise).\n * - Change `watchCircleType` to match the surrounding instrument ring style\n * (e.g. `triple` for compass contexts).\n *\n * @element obc-rate-of-turn\n * @stable\n */\n@customElement('obc-rate-of-turn')\nexport class ObcRateOfTurn extends LitElement {\n /**\n * Measured rate of turn in degrees per minute (positive = starboard).\n * When `undefined`, the legacy `rotationsPerMinute` value is used.\n */\n @property({type: Number}) rateOfTurnDegreesPerMinute: number | undefined;\n\n /**\n * Visual amplification applied to the spinning dot animation. Default `18`\n * keeps the legacy visual feel (≈1 rpm at 20°/min).\n */\n @property({type: Number}) rotDotAnimationFactor: number = 18;\n\n /**\n * @deprecated Use `rateOfTurnDegreesPerMinute` (and optionally\n * `rotDotAnimationFactor`) instead. Takes effect only when\n * `rateOfTurnDegreesPerMinute` is `undefined`.\n */\n @property({type: Number}) rotationsPerMinute: number = 1;\n\n @property({type: String}) rotType: RotType = RotType.dots;\n @property({type: String}) rotPosition: RotPosition = RotPosition.scale;\n @property({type: String}) priority: Priority = Priority.regular;\n @property({type: Number}) barStartAngle: number = 0;\n @property({type: Number}) barEndAngle: number = 30;\n @property({type: String}) watchCircleType: WatchCircleType =\n WatchCircleType.single;\n @property({type: Boolean}) rotPortStarboard: boolean = false;\n @property({type: Number}) rotAtZeroDeadband: number = ROT_ZERO_DEADBAND_DEG;\n /**\n * When `true`, shows a bar in the ring band from the twelve o'clock\n * position to the measured rate of turn, with a needle marker at its end\n * and sector tickmarks. Pairs with `watchCircleType=\"double\"` for the\n * banded face — or `\"triple\"` when `rotPosition` is `innerCircle`, so the\n * dots get their inner track too. Driven by `rateOfTurnDegreesPerMinute`\n * only.\n */\n @property({type: Boolean}) hasTrackBar: boolean = false;\n /**\n * Bar-extent reference value in **degrees per minute**: the track bar\n * reaches ±`rotArcExtent` when the measured ROT equals ±`rotMaxValue`.\n * Default `60` aligns with ES-TRIN 2025/1 Art. 3.02.\n * @availableWhen hasTrackBar==true\n */\n @property({type: Number}) rotMaxValue: number = 60;\n /**\n * Arc extent of the track bar in degrees per direction. Default `60`.\n * @availableWhen hasTrackBar==true\n */\n @property({type: Number}) rotArcExtent: number = 60;\n /**\n * When `true`, shows a centered `<obc-readout>` with the measured rate of\n * turn. Shows a dash while `rateOfTurnDegreesPerMinute` is unset.\n */\n @property({type: Boolean}) hasReadout: boolean = false;\n /**\n * Readout label. Default `ROT`.\n * @availableWhen hasReadout==true\n */\n @property({type: String}) label = 'ROT';\n /**\n * Readout unit. Default `DEG/min`.\n * @availableWhen hasReadout==true\n */\n @property({type: String}) unit = 'DEG/min';\n /**\n * Number of fraction digits shown in the readout. Default `0`.\n * @availableWhen hasReadout==true\n */\n @property({type: Number}) fractionDigits = 0;\n\n private get trackBarAngle(): number {\n const max = this.rotMaxValue || 1;\n const rot = this.rateOfTurnDegreesPerMinute ?? 0;\n const ratio = Math.max(-1, Math.min(1, rot / max));\n return ratio * this.rotArcExtent;\n }\n\n private get trackBarColor(): string {\n if (this.rotPortStarboard) {\n const rot = this.rateOfTurnDegreesPerMinute ?? 0;\n if (rot > 0) {\n return 'var(--instrument-starboard-secondary-color)';\n }\n if (rot < 0) {\n return 'var(--instrument-port-secondary-color)';\n }\n }\n return this.priority === Priority.enhanced\n ? 'var(--instrument-enhanced-tertiary-color)'\n : 'var(--instrument-regular-tertiary-color)';\n }\n\n private get trackNeedleColor(): string {\n if (this.rotPortStarboard) {\n const rot = this.rateOfTurnDegreesPerMinute ?? 0;\n if (rot > 0) {\n return 'var(--instrument-starboard-primary-color)';\n }\n if (rot < 0) {\n return 'var(--instrument-port-primary-color)';\n }\n return 'var(--instrument-regular-secondary-color)';\n }\n return this.priority === Priority.enhanced\n ? 'var(--instrument-enhanced-secondary-color)'\n : 'var(--instrument-regular-secondary-color)';\n }\n\n private get trackTickmarks(): Tickmark[] {\n const ticks: Tickmark[] = [{angle: 0, type: TickmarkType.main}];\n for (let angle = 30; angle <= this.rotArcExtent; angle += 30) {\n ticks.push({angle, type: TickmarkType.primary});\n ticks.push({angle: -angle, type: TickmarkType.primary});\n }\n return ticks;\n }\n\n static override styles = [\n unsafeCSS(instrumentReadoutStyle),\n centerReadoutStyles,\n css`\n * {\n box-sizing: border-box;\n }\n\n .container {\n position: relative;\n width: 100%;\n height: 100%;\n }\n\n .container > * {\n position: absolute;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n }\n\n .center-readout-overlay {\n display: flex;\n align-items: center;\n justify-content: center;\n pointer-events: none;\n }\n `,\n ];\n\n override render() {\n return html`<div class=\"container\">\n <obc-watch\n .watchCircleType=${this.watchCircleType}\n .priority=${this.priority}\n .tickmarks=${this.hasTrackBar ? this.trackTickmarks : []}\n .barAreas=${this.hasTrackBar\n ? [\n {\n startAngle: 0,\n endAngle: this.trackBarAngle,\n fillColor: this.trackBarColor,\n },\n ]\n : []}\n .needles=${this.hasTrackBar\n ? [\n {\n angle: this.trackBarAngle,\n fillColor: this.trackNeedleColor,\n strokeColor: 'var(--border-silhouette-color)',\n },\n ]\n : []}\n .rotType=${this.rotType}\n .rotPosition=${this.rotPosition}\n .rotStartAngle=${this.barStartAngle}\n .rotEndAngle=${this.barEndAngle}\n .rateOfTurnDegreesPerMinute=${this.rateOfTurnDegreesPerMinute}\n .rotDotAnimationFactor=${this.rotDotAnimationFactor}\n .rotationsPerMinute=${this.rotationsPerMinute}\n .rotPortStarboard=${this.rotPortStarboard}\n .rotAtZeroDeadband=${this.rotAtZeroDeadband}\n ></obc-watch>\n ${this.hasReadout\n ? html`<div class=\"center-readout-overlay\">\n ${renderCenterReadouts([\n {\n value: this.rateOfTurnDegreesPerMinute ?? null,\n label: this.label,\n unit: this.unit,\n fractionDigits: this.fractionDigits,\n size: ReadoutSize.large,\n priority: this.priority,\n centerValue: true,\n centerMeta: true,\n },\n ])}\n </div>`\n : nothing}\n </div>`;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'obc-rate-of-turn': ObcRateOfTurn;\n }\n}\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;AA6DO,IAAM,gBAAN,cAA4B,WAAW;AAAA,EAAvC,cAAA;AAAA,UAAA,GAAA,SAAA;AAWqB,SAAA,wBAAgC;AAOhC,SAAA,qBAA6B;AAE7B,SAAA,UAAmB,QAAQ;AAC3B,SAAA,cAA2B,YAAY;AACvC,SAAA,WAAqB,SAAS;AAC9B,SAAA,gBAAwB;AACxB,SAAA,cAAsB;AACtB,SAAA,kBACxB,gBAAgB;AACS,SAAA,mBAA4B;AAC7B,SAAA,oBAA4B;AAS3B,SAAA,cAAuB;AAOxB,SAAA,cAAsB;AAKtB,SAAA,eAAuB;AAKtB,SAAA,aAAsB;AAKvB,SAAA,QAAQ;AAKR,SAAA,OAAO;AAKP,SAAA,iBAAiB;AAAA,EAAA;AAAA,EAE3C,IAAY,gBAAwB;AAClC,UAAM,MAAM,KAAK,eAAe;AAChC,UAAM,MAAM,KAAK,8BAA8B;AAC/C,UAAM,QAAQ,KAAK,IAAI,IAAI,KAAK,IAAI,GAAG,MAAM,GAAG,CAAC;AACjD,WAAO,QAAQ,KAAK;AAAA,EACtB;AAAA,EAEA,IAAY,gBAAwB;AAClC,QAAI,KAAK,kBAAkB;AACzB,YAAM,MAAM,KAAK,8BAA8B;AAC/C,UAAI,MAAM,GAAG;AACX,eAAO;AAAA,MACT;AACA,UAAI,MAAM,GAAG;AACX,eAAO;AAAA,MACT;AAAA,IACF;AACA,WAAO,KAAK,aAAa,SAAS,WAC9B,8CACA;AAAA,EACN;AAAA,EAEA,IAAY,mBAA2B;AACrC,QAAI,KAAK,kBAAkB;AACzB,YAAM,MAAM,KAAK,8BAA8B;AAC/C,UAAI,MAAM,GAAG;AACX,eAAO;AAAA,MACT;AACA,UAAI,MAAM,GAAG;AACX,eAAO;AAAA,MACT;AACA,aAAO;AAAA,IACT;AACA,WAAO,KAAK,aAAa,SAAS,WAC9B,+CACA;AAAA,EACN;AAAA,EAEA,IAAY,iBAA6B;AACvC,UAAM,QAAoB,CAAC,EAAC,OAAO,GAAG,MAAM,aAAa,MAAK;AAC9D,aAAS,QAAQ,IAAI,SAAS,KAAK,cAAc,SAAS,IAAI;AAC5D,YAAM,KAAK,EAAC,OAAO,MAAM,aAAa,SAAQ;AAC9C,YAAM,KAAK,EAAC,OAAO,CAAC,OAAO,MAAM,aAAa,SAAQ;AAAA,IACxD;AACA,WAAO;AAAA,EACT;AAAA,EAiCS,SAAS;AAChB,WAAO;AAAA;AAAA,2BAEgB,KAAK,eAAe;AAAA,oBAC3B,KAAK,QAAQ;AAAA,qBACZ,KAAK,cAAc,KAAK,iBAAiB,CAAA,CAAE;AAAA,oBAC5C,KAAK,cACb;AAAA,MACE;AAAA,QACE,YAAY;AAAA,QACZ,UAAU,KAAK;AAAA,QACf,WAAW,KAAK;AAAA,MAAA;AAAA,IAClB,IAEF,CAAA,CAAE;AAAA,mBACK,KAAK,cACZ;AAAA,MACE;AAAA,QACE,OAAO,KAAK;AAAA,QACZ,WAAW,KAAK;AAAA,QAChB,aAAa;AAAA,MAAA;AAAA,IACf,IAEF,CAAA,CAAE;AAAA,mBACK,KAAK,OAAO;AAAA,uBACR,KAAK,WAAW;AAAA,yBACd,KAAK,aAAa;AAAA,uBACpB,KAAK,WAAW;AAAA,sCACD,KAAK,0BAA0B;AAAA,iCACpC,KAAK,qBAAqB;AAAA,8BAC7B,KAAK,kBAAkB;AAAA,4BACzB,KAAK,gBAAgB;AAAA,6BACpB,KAAK,iBAAiB;AAAA;AAAA,QAE3C,KAAK,aACH;AAAA,cACI,qBAAqB;AAAA,MACrB;AAAA,QACE,OAAO,KAAK,8BAA8B;AAAA,QAC1C,OAAO,KAAK;AAAA,QACZ,MAAM,KAAK;AAAA,QACX,gBAAgB,KAAK;AAAA,QACrB,MAAM,YAAY;AAAA,QAClB,UAAU,KAAK;AAAA,QACf,aAAa;AAAA,QACb,YAAY;AAAA,MAAA;AAAA,IACd,CACD,CAAC;AAAA,oBAEJ,OAAO;AAAA;AAAA,EAEf;AACF;AAzMa,cAsHK,SAAS;AAAA,EACvB,UAAU,sBAAsB;AAAA,EAChC;AAAA,EACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA0BF;AA9I0B,gBAAA;AAAA,EAAzB,SAAS,EAAC,MAAM,OAAA,CAAO;AAAA,GALb,cAKe,WAAA,8BAAA,CAAA;AAMA,gBAAA;AAAA,EAAzB,SAAS,EAAC,MAAM,OAAA,CAAO;AAAA,GAXb,cAWe,WAAA,yBAAA,CAAA;AAOA,gBAAA;AAAA,EAAzB,SAAS,EAAC,MAAM,OAAA,CAAO;AAAA,GAlBb,cAkBe,WAAA,sBAAA,CAAA;AAEA,gBAAA;AAAA,EAAzB,SAAS,EAAC,MAAM,OAAA,CAAO;AAAA,GApBb,cAoBe,WAAA,WAAA,CAAA;AACA,gBAAA;AAAA,EAAzB,SAAS,EAAC,MAAM,OAAA,CAAO;AAAA,GArBb,cAqBe,WAAA,eAAA,CAAA;AACA,gBAAA;AAAA,EAAzB,SAAS,EAAC,MAAM,OAAA,CAAO;AAAA,GAtBb,cAsBe,WAAA,YAAA,CAAA;AACA,gBAAA;AAAA,EAAzB,SAAS,EAAC,MAAM,OAAA,CAAO;AAAA,GAvBb,cAuBe,WAAA,iBAAA,CAAA;AACA,gBAAA;AAAA,EAAzB,SAAS,EAAC,MAAM,OAAA,CAAO;AAAA,GAxBb,cAwBe,WAAA,eAAA,CAAA;AACA,gBAAA;AAAA,EAAzB,SAAS,EAAC,MAAM,OAAA,CAAO;AAAA,GAzBb,cAyBe,WAAA,mBAAA,CAAA;AAEC,gBAAA;AAAA,EAA1B,SAAS,EAAC,MAAM,QAAA,CAAQ;AAAA,GA3Bd,cA2BgB,WAAA,oBAAA,CAAA;AACD,gBAAA;AAAA,EAAzB,SAAS,EAAC,MAAM,OAAA,CAAO;AAAA,GA5Bb,cA4Be,WAAA,qBAAA,CAAA;AASC,gBAAA;AAAA,EAA1B,SAAS,EAAC,MAAM,QAAA,CAAQ;AAAA,GArCd,cAqCgB,WAAA,eAAA,CAAA;AAOD,gBAAA;AAAA,EAAzB,SAAS,EAAC,MAAM,OAAA,CAAO;AAAA,GA5Cb,cA4Ce,WAAA,eAAA,CAAA;AAKA,gBAAA;AAAA,EAAzB,SAAS,EAAC,MAAM,OAAA,CAAO;AAAA,GAjDb,cAiDe,WAAA,gBAAA,CAAA;AAKC,gBAAA;AAAA,EAA1B,SAAS,EAAC,MAAM,QAAA,CAAQ;AAAA,GAtDd,cAsDgB,WAAA,cAAA,CAAA;AAKD,gBAAA;AAAA,EAAzB,SAAS,EAAC,MAAM,OAAA,CAAO;AAAA,GA3Db,cA2De,WAAA,SAAA,CAAA;AAKA,gBAAA;AAAA,EAAzB,SAAS,EAAC,MAAM,OAAA,CAAO;AAAA,GAhEb,cAgEe,WAAA,QAAA,CAAA;AAKA,gBAAA;AAAA,EAAzB,SAAS,EAAC,MAAM,OAAA,CAAO;AAAA,GArEb,cAqEe,WAAA,kBAAA,CAAA;AArEf,gBAAN,gBAAA;AAAA,EADN,cAAc,kBAAkB;AAAA,GACpB,aAAA;"}
|
|
@@ -139,6 +139,12 @@ export declare class ObcTopViewPropulsion extends LitElement {
|
|
|
139
139
|
private get secondaryColor();
|
|
140
140
|
private renderSecondaryArc;
|
|
141
141
|
private renderLoadingArc;
|
|
142
|
+
/**
|
|
143
|
+
* Thin outline on the track band's inner edge, always shown per the
|
|
144
|
+
* design's track face. Drawn on the overlay because the watch paints its
|
|
145
|
+
* band bars over the ring circles, which would swallow a watch-side line.
|
|
146
|
+
*/
|
|
147
|
+
private renderInnerRingLine;
|
|
142
148
|
private renderPropeller;
|
|
143
149
|
render(): import('lit-html').TemplateResult<1>;
|
|
144
150
|
static styles: import('lit').CSSResult;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"top-view-propulsion.d.ts","sourceRoot":"","sources":["../../../src/navigation-instruments/top-view-propulsion/top-view-propulsion.ts"],"names":[],"mappings":"AAAA,OAAO,EAAY,UAAU,EAAqB,MAAM,KAAK,CAAC;AAE9D,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,KAAK,CAAC;AAUxC,OAAO,EAAC,eAAe,EAAE,QAAQ,EAAC,MAAM,aAAa,CAAC;AAEtD,OAAO,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"top-view-propulsion.d.ts","sourceRoot":"","sources":["../../../src/navigation-instruments/top-view-propulsion/top-view-propulsion.ts"],"names":[],"mappings":"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"}
|
|
@@ -4,8 +4,8 @@ import { ResizeController } from "@lit-labs/observers/resize-controller.js";
|
|
|
4
4
|
import { observeInnerBox, applyPinnedHostSize, computeRadialFrame, measureContainerPx, estimateLabelWidthPx } from "../../svghelpers/radial-frame.js";
|
|
5
5
|
import { InstrumentState, Priority } from "../types.js";
|
|
6
6
|
import { SetpointBundle } from "../../svghelpers/setpoint-bundle.js";
|
|
7
|
-
import { OUTER_RING_RADIUS } from "../watch/watch.js";
|
|
8
|
-
import { PRIMARY_SUBBAND_INNER_RADIUS, PRIMARY_SUBBAND_NEEDLE_LENGTH, LANE_DIVIDER_RADIUS, LANE_DIVIDER_WIDTH, renderSecondaryLine, arcPath } from "../watch/secondary-lane.js";
|
|
7
|
+
import { WatchCircleType, OUTER_RING_RADIUS } from "../watch/watch.js";
|
|
8
|
+
import { PRIMARY_SUBBAND_INNER_RADIUS, PRIMARY_SUBBAND_NEEDLE_LENGTH, LANE_DIVIDER_RADIUS, LANE_DIVIDER_WIDTH, renderSecondaryLine, arcPath, BAND_INNER_RADIUS } from "../watch/secondary-lane.js";
|
|
9
9
|
import { TickmarkStyle, TickmarkType } from "../watch/tickmark.js";
|
|
10
10
|
import { PropellerImage, propellerImages } from "../watch/propeller.js";
|
|
11
11
|
import { customElement } from "../../decorator.js";
|
|
@@ -248,6 +248,20 @@ let ObcTopViewPropulsion = class extends LitElement {
|
|
|
248
248
|
stroke-linecap="round"
|
|
249
249
|
></path>`;
|
|
250
250
|
}
|
|
251
|
+
/**
|
|
252
|
+
* Thin outline on the track band's inner edge, always shown per the
|
|
253
|
+
* design's track face. Drawn on the overlay because the watch paints its
|
|
254
|
+
* band bars over the ring circles, which would swallow a watch-side line.
|
|
255
|
+
*/
|
|
256
|
+
renderInnerRingLine() {
|
|
257
|
+
return svg`<circle
|
|
258
|
+
r=${BAND_INNER_RADIUS}
|
|
259
|
+
fill="none"
|
|
260
|
+
stroke="var(--instrument-frame-tertiary-color)"
|
|
261
|
+
stroke-width="1"
|
|
262
|
+
vector-effect="non-scaling-stroke"
|
|
263
|
+
></circle>`;
|
|
264
|
+
}
|
|
251
265
|
renderPropeller() {
|
|
252
266
|
return svg`<g transform="scale(${PROPELLER_SCALE}) translate(-80 -80)">${propellerImages[this.propeller]}</g>`;
|
|
253
267
|
}
|
|
@@ -268,6 +282,7 @@ let ObcTopViewPropulsion = class extends LitElement {
|
|
|
268
282
|
<obc-watch
|
|
269
283
|
.touching=${this.touching}
|
|
270
284
|
.arcFrame=${frame}
|
|
285
|
+
.watchCircleType=${WatchCircleType.double}
|
|
271
286
|
.tickmarks=${shownTickmarks}
|
|
272
287
|
.state=${this.state}
|
|
273
288
|
.priority=${this.priority}
|
|
@@ -285,8 +300,8 @@ let ObcTopViewPropulsion = class extends LitElement {
|
|
|
285
300
|
.tickmarkStyle=${this.tickmarkStyle}
|
|
286
301
|
></obc-watch>
|
|
287
302
|
<svg viewBox=${frame.viewBox} xmlns="http://www.w3.org/2000/svg">
|
|
288
|
-
${this.
|
|
289
|
-
${this.renderPropeller()}
|
|
303
|
+
${this.renderInnerRingLine()} ${this.renderLoadingArc()}
|
|
304
|
+
${this.renderSecondaryArc()} ${this.renderPropeller()}
|
|
290
305
|
</svg>
|
|
291
306
|
</div>
|
|
292
307
|
`;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"top-view-propulsion.js","sources":["../../../src/navigation-instruments/top-view-propulsion/top-view-propulsion.ts"],"sourcesContent":["import {html, svg, LitElement, nothing, unsafeCSS} from 'lit';\nimport {property} from 'lit/decorators.js';\nimport type {PropertyValues} from 'lit';\nimport {ResizeController} from '@lit-labs/observers/resize-controller.js';\nimport {\n applyPinnedHostSize,\n computeRadialFrame,\n estimateLabelWidthPx,\n measureContainerPx,\n observeInnerBox,\n type RadialFrame,\n} from '../../svghelpers/radial-frame.js';\nimport {InstrumentState, Priority} from '../types.js';\nimport {SetpointBundle} from '../../svghelpers/setpoint-bundle.js';\nimport '../watch/watch.js';\nimport {\n OUTER_RING_RADIUS,\n type WatchBarArea,\n type WatchNeedle,\n} from '../watch/watch.js';\nimport {\n LANE_DIVIDER_RADIUS,\n LANE_DIVIDER_WIDTH,\n PRIMARY_SUBBAND_INNER_RADIUS,\n PRIMARY_SUBBAND_NEEDLE_LENGTH,\n arcPath,\n renderSecondaryLine,\n} from '../watch/secondary-lane.js';\nimport {Tickmark, TickmarkStyle, TickmarkType} from '../watch/tickmark.js';\nimport {PropellerImage, propellerImages} from '../watch/propeller.js';\nimport {customElement} from '../../decorator.js';\nimport componentStyle from './top-view-propulsion.css?inline';\n\nexport enum TopViewPropulsionType {\n power = 'power',\n pitchRpm = 'pitch-rpm',\n}\n\nconst FULL_CIRCLE_END_ANGLE = 359.999;\nconst LOADING_ARC_RADIUS = (OUTER_RING_RADIUS + 320 / 2) / 2;\nconst PROPELLER_SCALE = 224 / 160;\n\nfunction percentToAngle(value: number): number {\n if (!Number.isFinite(value)) {\n return 0;\n }\n return Math.max(-100, Math.min(100, value)) * 1.8;\n}\n\n/**\n * Top View Propulsion - a propulsion gauge on a circular watch face with a\n * top-view propeller in the center.\n *\n * ## Features / Variants\n * - `power` type: signed percent value shown as a tinted arc on the inner\n * track from the thick zero line, with a needle at the arc end.\n * - `pitch-rpm` type: rpm on the primary track (same rendering as power)\n * plus pitch as a thin secondary arc at the track's inner edge with its\n * own zero mark and end nub.\n * - Interchangeable center propeller art (`PropellerImage`).\n * - Full setpoint support (marker, adjustment preview, at-setpoint states)\n * for the primary axis (power or rpm).\n * - Loading progress arc on the outer ring while `state` is `loading`.\n *\n * ## Usage Guidelines\n * Use for a propulsion unit overview. For an azimuthing unit with a\n * direction bar, use `obc-azimuth-thruster` instead.\n *\n * @experimental The API of this component is under design review and may\n * change in a future release.\n */\n@customElement('obc-top-view-propulsion')\nexport class ObcTopViewPropulsion extends LitElement {\n @property({type: String}) type: TopViewPropulsionType =\n TopViewPropulsionType.power;\n\n /**\n * Signed power in percent: 0 at the top, positive clockwise, ±100% = ±180°.\n * @availableWhen type==power\n */\n @property({type: Number}) power = 0;\n /** @availableWhen type==power */\n @property({type: Number}) powerSetpoint: number | undefined;\n /** @availableWhen type==power && powerSetpoint!=undefined */\n @property({type: Number}) newPowerSetpoint: number | undefined;\n /** @availableWhen type==power && powerSetpoint!=undefined && autoAtPowerSetpoint==false */\n @property({type: Boolean}) atPowerSetpoint = false;\n /** @availableWhen type==power && powerSetpoint!=undefined */\n @property({type: Number}) powerSetpointAtZeroDeadband = 0.1;\n /** @availableWhen type==power && powerSetpoint!=undefined */\n @property({type: Boolean}) powerSetpointOverride = false;\n /** @availableWhen type==power && powerSetpoint!=undefined */\n @property({type: Boolean, attribute: false}) autoAtPowerSetpoint = true;\n /** @availableWhen type==power && powerSetpoint!=undefined && autoAtPowerSetpoint==true */\n @property({type: Number}) autoAtPowerSetpointDeadband = 1;\n\n /**\n * Signed rpm in percent of the maximum: 0 at the top, positive clockwise,\n * ±100% = ±180°. Shown on the primary track.\n * @availableWhen type==pitch-rpm\n */\n @property({type: Number}) rpm = 0;\n /** @availableWhen type==pitch-rpm */\n @property({type: Number}) rpmSetpoint: number | undefined;\n /** @availableWhen type==pitch-rpm && rpmSetpoint!=undefined */\n @property({type: Number}) newRpmSetpoint: number | undefined;\n /** @availableWhen type==pitch-rpm && rpmSetpoint!=undefined && autoAtRpmSetpoint==false */\n @property({type: Boolean}) atRpmSetpoint = false;\n /** @availableWhen type==pitch-rpm && rpmSetpoint!=undefined */\n @property({type: Number}) rpmSetpointAtZeroDeadband = 0.1;\n /** @availableWhen type==pitch-rpm && rpmSetpoint!=undefined */\n @property({type: Boolean}) rpmSetpointOverride = false;\n /** @availableWhen type==pitch-rpm && rpmSetpoint!=undefined */\n @property({type: Boolean, attribute: false}) autoAtRpmSetpoint = true;\n /** @availableWhen type==pitch-rpm && rpmSetpoint!=undefined && autoAtRpmSetpoint==true */\n @property({type: Number}) autoAtRpmSetpointDeadband = 1;\n\n /**\n * Signed pitch in percent: 0 at the top, positive clockwise, ±100% = ±180°.\n * Shown as the thin secondary arc.\n * @availableWhen type==pitch-rpm\n */\n @property({type: Number}) pitch = 0;\n\n /** @availableWhen powerSetpoint!=undefined || rpmSetpoint!=undefined */\n @property({type: Boolean}) touching = false;\n /** @availableWhen powerSetpoint!=undefined || rpmSetpoint!=undefined */\n @property({type: Boolean}) animateSetpoint = false;\n\n @property({type: String}) state: InstrumentState = InstrumentState.active;\n @property({type: String}) priority: Priority = Priority.regular;\n /**\n * Loading progress in percent, shown as an arc on the outer ring.\n * @availableWhen state==loading\n */\n @property({type: Number}) loading = 0;\n\n /**\n * Interval (in degrees) for primary tickmarks.\n * When undefined or <= 0, no primary tickmarks are shown (only the zero line).\n */\n @property({type: Number}) primaryTickmarkInterval: number | undefined = 90;\n /**\n * Interval (in degrees) for secondary tickmarks.\n * When undefined or <= 0, no secondary tickmarks are shown.\n */\n @property({type: Number}) secondaryTickmarkInterval: number | undefined =\n undefined;\n /**\n * Interval (in degrees) for tertiary tickmarks.\n * When undefined or <= 0, no tertiary tickmarks are shown.\n */\n @property({type: Number}) tertiaryTickmarkInterval: number | undefined =\n undefined;\n @property({type: Boolean}) showLabels = false;\n @property({type: Boolean}) tickmarksInside = false;\n @property({type: String}) tickmarkStyle: TickmarkStyle =\n TickmarkStyle.regular;\n @property({type: Boolean, attribute: false}) hasLabelSpacer = true;\n\n @property({type: String}) propeller: PropellerImage =\n PropellerImage.fourBlade;\n\n /**\n * Outer-ring diameter in CSS pixels. When set, the instrument renders at a\n * fixed intrinsic size derived from the ring, arc shape and label reserve —\n * so instruments sharing the same value have identical ring circumference\n * regardless of label width or arc extent (like obc-donut-chart's\n * fixedHeight). When unset (default), the instrument fills its container.\n */\n @property({type: Number, attribute: 'face-diameter'})\n faceDiameter: number | undefined;\n\n private _powerSp = new SetpointBundle({\n defaultDeadband: 1,\n defaultZeroDeadband: 0.1,\n onAnimationEnd: () => this.requestUpdate(),\n });\n private _rpmSp = new SetpointBundle({\n defaultDeadband: 1,\n defaultZeroDeadband: 0.1,\n onAnimationEnd: () => this.requestUpdate(),\n });\n\n private _frame: RadialFrame | undefined;\n private _hostSizePinned = false;\n private _resizeController = new ResizeController(this, {});\n\n override firstUpdated(changed: PropertyValues): void {\n super.firstUpdated(changed);\n observeInnerBox(this._resizeController, this.renderRoot);\n }\n\n override willUpdate(changed: PropertyValues): void {\n super.willUpdate(changed);\n this._powerSp.sync({\n setpoint: this.powerSetpoint,\n newSetpoint: this.newPowerSetpoint,\n atSetpoint: this.atPowerSetpoint,\n touching: this.touching,\n autoAtSetpoint: this.autoAtPowerSetpoint,\n autoAtSetpointDeadband: this.autoAtPowerSetpointDeadband,\n setpointAtZeroDeadband: this.powerSetpointAtZeroDeadband,\n setpointOverride: this.powerSetpointOverride,\n animateSetpoint: this.animateSetpoint,\n });\n this._rpmSp.sync({\n setpoint: this.rpmSetpoint,\n newSetpoint: this.newRpmSetpoint,\n atSetpoint: this.atRpmSetpoint,\n touching: this.touching,\n autoAtSetpoint: this.autoAtRpmSetpoint,\n autoAtSetpointDeadband: this.autoAtRpmSetpointDeadband,\n setpointAtZeroDeadband: this.rpmSetpointAtZeroDeadband,\n setpointOverride: this.rpmSetpointOverride,\n animateSetpoint: this.animateSetpoint,\n });\n }\n\n private get isPitchRpm(): boolean {\n return this.type === TopViewPropulsionType.pitchRpm;\n }\n\n private get primaryValue(): number {\n return this.isPitchRpm ? this.rpm : this.power;\n }\n\n private get primarySp(): SetpointBundle {\n return this.isPitchRpm ? this._rpmSp : this._powerSp;\n }\n\n private get primarySetpoint(): number | undefined {\n return this.isPitchRpm ? this.rpmSetpoint : this.powerSetpoint;\n }\n\n private get primaryNewSetpoint(): number | undefined {\n return this.isPitchRpm ? this.newRpmSetpoint : this.newPowerSetpoint;\n }\n\n private get primaryZeroDeadband(): number {\n return this.isPitchRpm\n ? this.rpmSetpointAtZeroDeadband\n : this.powerSetpointAtZeroDeadband;\n }\n\n private get primarySetpointOverride(): boolean {\n return this.isPitchRpm\n ? this.rpmSetpointOverride\n : this.powerSetpointOverride;\n }\n\n override updated(changed: PropertyValues): void {\n super.updated(changed);\n this._hostSizePinned = applyPinnedHostSize(\n this,\n this._frame,\n this._hostSizePinned\n );\n }\n\n override disconnectedCallback(): void {\n super.disconnectedCallback();\n this._powerSp.dispose();\n this._rpmSp.dispose();\n }\n\n private get isActive(): boolean {\n return (\n this.state !== InstrumentState.loading &&\n this.state !== InstrumentState.off\n );\n }\n\n private get isEnhanced(): boolean {\n return this.priority === Priority.enhanced;\n }\n\n private getTickmarks(): Tickmark[] {\n const tickmarks: Tickmark[] = [];\n const skipAngles: number[] = [];\n\n const labelText = (angle: number): string | undefined => {\n if (!this.showLabels) return undefined;\n return angle <= 180 ? `${angle}` : `${angle - 360}`;\n };\n\n tickmarks.push({\n angle: 0,\n type: TickmarkType.zeroLineThick,\n text: this.showLabels ? '0' : undefined,\n color:\n this.isActive && this.isEnhanced\n ? 'var(--instrument-enhanced-tertiary-color)'\n : undefined,\n });\n skipAngles.push(0);\n\n const addInterval = (\n interval: number | undefined,\n type: TickmarkType,\n withLabels = false\n ) => {\n if (interval === undefined || interval <= 0 || !Number.isFinite(interval))\n return;\n for (let i = interval; i < 360; i += interval) {\n if (skipAngles.includes(i)) continue;\n tickmarks.push({\n angle: i,\n type,\n text: withLabels ? labelText(i) : undefined,\n });\n skipAngles.push(i);\n }\n };\n\n addInterval(this.primaryTickmarkInterval, TickmarkType.primary, true);\n addInterval(this.secondaryTickmarkInterval, TickmarkType.secondary);\n addInterval(this.tertiaryTickmarkInterval, TickmarkType.tertiary);\n\n return tickmarks;\n }\n\n private getBarAreas(): WatchBarArea[] {\n const areas: WatchBarArea[] = [\n {\n startAngle: 0,\n endAngle: FULL_CIRCLE_END_ANGLE,\n fillColor: 'var(--instrument-frame-secondary-color)',\n },\n ];\n const valueAngle = percentToAngle(this.primaryValue);\n if (this.isActive && Math.abs(valueAngle) > 0.1) {\n areas.push({\n startAngle: Math.min(0, valueAngle),\n endAngle: Math.max(0, valueAngle),\n fillColor: this.isEnhanced\n ? 'var(--instrument-enhanced-tertiary-color)'\n : 'var(--instrument-regular-tertiary-color)',\n innerRadius: this.isPitchRpm ? PRIMARY_SUBBAND_INNER_RADIUS : undefined,\n });\n }\n return areas;\n }\n\n private getNeedles(): WatchNeedle[] {\n const fill = !this.isActive\n ? 'var(--instrument-frame-tertiary-color)'\n : this.isEnhanced\n ? 'var(--instrument-enhanced-secondary-color)'\n : 'var(--instrument-regular-secondary-color)';\n const stroke = !this.isActive\n ? 'var(--border-silhouette-color)'\n : this.isEnhanced\n ? 'var(--instrument-enhanced-tertiary-color)'\n : 'var(--instrument-regular-tertiary-color)';\n return [\n {\n angle: percentToAngle(this.primaryValue),\n fillColor: fill,\n strokeColor: stroke,\n length: this.isPitchRpm ? PRIMARY_SUBBAND_NEEDLE_LENGTH : undefined,\n },\n ];\n }\n\n private get secondaryColor(): string {\n if (!this.isActive) {\n return 'var(--instrument-frame-tertiary-color)';\n }\n return this.isEnhanced\n ? 'var(--instrument-enhanced-secondary-color)'\n : 'var(--instrument-regular-secondary-color)';\n }\n\n private renderSecondaryArc() {\n if (!this.isPitchRpm) {\n return nothing;\n }\n const divider = svg`<circle\n r=${LANE_DIVIDER_RADIUS}\n fill=\"none\"\n stroke=\"var(--instrument-frame-primary-color)\"\n stroke-width=${LANE_DIVIDER_WIDTH}\n ></circle>`;\n const pitchAngle = this.isActive ? percentToAngle(this.pitch) : 0;\n return svg`\n ${divider}\n ${renderSecondaryLine({\n originAngle: 0,\n endAngle: pitchAngle,\n color: this.secondaryColor,\n })}\n `;\n }\n\n private renderLoadingArc() {\n if (this.state !== InstrumentState.loading || this.loading <= 0) {\n return nothing;\n }\n const endAngle = percentToAngle(Math.abs(this.loading)) * 2;\n return svg`<path\n d=${arcPath(LOADING_ARC_RADIUS, 0, Math.min(endAngle, FULL_CIRCLE_END_ANGLE))}\n fill=\"none\"\n stroke=${\n this.isEnhanced\n ? 'var(--instrument-enhanced-secondary-color)'\n : 'var(--instrument-regular-secondary-color)'\n }\n stroke-width=\"8\"\n stroke-linecap=\"round\"\n ></path>`;\n }\n\n private renderPropeller() {\n return svg`<g transform=\"scale(${PROPELLER_SCALE}) translate(-80 -80)\">${\n propellerImages[this.propeller]\n }</g>`;\n }\n\n override render() {\n const tickmarks = this.getTickmarks();\n\n const frame = computeRadialFrame({\n basePadding: this.hasLabelSpacer ? 24 : 16,\n labelWidthPx:\n this.hasLabelSpacer && !this.tickmarksInside\n ? estimateLabelWidthPx(tickmarks.map((t) => t.text))\n : 0,\n containerPx: measureContainerPx(this),\n faceDiameter: this.faceDiameter,\n });\n this._frame = frame;\n const shownTickmarks = frame.labelsHidden\n ? tickmarks.map((t) => ({...t, text: undefined}))\n : tickmarks;\n\n const setpointAngle =\n this.primarySetpoint !== undefined\n ? percentToAngle(this.primarySetpoint)\n : undefined;\n const newSetpointAngle =\n this.primaryNewSetpoint !== undefined\n ? percentToAngle(this.primaryNewSetpoint)\n : undefined;\n\n return html`\n <div class=\"container\">\n <obc-watch\n .touching=${this.touching}\n .arcFrame=${frame}\n .tickmarks=${shownTickmarks}\n .state=${this.state}\n .priority=${this.priority}\n .barAreas=${this.getBarAreas()}\n .needles=${this.getNeedles()}\n .angleSetpoint=${setpointAngle}\n .newAngleSetpoint=${newSetpointAngle}\n .atAngleSetpoint=${this.primarySp.computeAtSetpoint(\n this.primaryValue\n )}\n .angleSetpointAtZeroDeadband=${this.primaryZeroDeadband * 1.8}\n .setpointOverride=${this.primarySetpointOverride}\n .animateSetpoint=${this.animateSetpoint}\n .tickmarksInside=${this.tickmarksInside}\n .tickmarkStyle=${this.tickmarkStyle}\n ></obc-watch>\n <svg viewBox=${frame.viewBox} xmlns=\"http://www.w3.org/2000/svg\">\n ${this.renderLoadingArc()} ${this.renderSecondaryArc()}\n ${this.renderPropeller()}\n </svg>\n </div>\n `;\n }\n\n static override styles = unsafeCSS(componentStyle);\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'obc-top-view-propulsion': ObcTopViewPropulsion;\n }\n}\n"],"names":["TopViewPropulsionType"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"top-view-propulsion.js","sources":["../../../src/navigation-instruments/top-view-propulsion/top-view-propulsion.ts"],"sourcesContent":["import {html, svg, LitElement, nothing, unsafeCSS} from 'lit';\nimport {property} from 'lit/decorators.js';\nimport type {PropertyValues} from 'lit';\nimport {ResizeController} from '@lit-labs/observers/resize-controller.js';\nimport {\n applyPinnedHostSize,\n computeRadialFrame,\n estimateLabelWidthPx,\n measureContainerPx,\n observeInnerBox,\n type RadialFrame,\n} from '../../svghelpers/radial-frame.js';\nimport {InstrumentState, Priority} from '../types.js';\nimport {SetpointBundle} from '../../svghelpers/setpoint-bundle.js';\nimport '../watch/watch.js';\nimport {\n OUTER_RING_RADIUS,\n WatchCircleType,\n type WatchBarArea,\n type WatchNeedle,\n} from '../watch/watch.js';\nimport {\n BAND_INNER_RADIUS,\n LANE_DIVIDER_RADIUS,\n LANE_DIVIDER_WIDTH,\n PRIMARY_SUBBAND_INNER_RADIUS,\n PRIMARY_SUBBAND_NEEDLE_LENGTH,\n arcPath,\n renderSecondaryLine,\n} from '../watch/secondary-lane.js';\nimport {Tickmark, TickmarkStyle, TickmarkType} from '../watch/tickmark.js';\nimport {PropellerImage, propellerImages} from '../watch/propeller.js';\nimport {customElement} from '../../decorator.js';\nimport componentStyle from './top-view-propulsion.css?inline';\n\nexport enum TopViewPropulsionType {\n power = 'power',\n pitchRpm = 'pitch-rpm',\n}\n\nconst FULL_CIRCLE_END_ANGLE = 359.999;\nconst LOADING_ARC_RADIUS = (OUTER_RING_RADIUS + 320 / 2) / 2;\nconst PROPELLER_SCALE = 224 / 160;\n\nfunction percentToAngle(value: number): number {\n if (!Number.isFinite(value)) {\n return 0;\n }\n return Math.max(-100, Math.min(100, value)) * 1.8;\n}\n\n/**\n * Top View Propulsion - a propulsion gauge on a circular watch face with a\n * top-view propeller in the center.\n *\n * ## Features / Variants\n * - `power` type: signed percent value shown as a tinted arc on the inner\n * track from the thick zero line, with a needle at the arc end.\n * - `pitch-rpm` type: rpm on the primary track (same rendering as power)\n * plus pitch as a thin secondary arc at the track's inner edge with its\n * own zero mark and end nub.\n * - Interchangeable center propeller art (`PropellerImage`).\n * - Full setpoint support (marker, adjustment preview, at-setpoint states)\n * for the primary axis (power or rpm).\n * - Loading progress arc on the outer ring while `state` is `loading`.\n *\n * ## Usage Guidelines\n * Use for a propulsion unit overview. For an azimuthing unit with a\n * direction bar, use `obc-azimuth-thruster` instead.\n *\n * @experimental The API of this component is under design review and may\n * change in a future release.\n */\n@customElement('obc-top-view-propulsion')\nexport class ObcTopViewPropulsion extends LitElement {\n @property({type: String}) type: TopViewPropulsionType =\n TopViewPropulsionType.power;\n\n /**\n * Signed power in percent: 0 at the top, positive clockwise, ±100% = ±180°.\n * @availableWhen type==power\n */\n @property({type: Number}) power = 0;\n /** @availableWhen type==power */\n @property({type: Number}) powerSetpoint: number | undefined;\n /** @availableWhen type==power && powerSetpoint!=undefined */\n @property({type: Number}) newPowerSetpoint: number | undefined;\n /** @availableWhen type==power && powerSetpoint!=undefined && autoAtPowerSetpoint==false */\n @property({type: Boolean}) atPowerSetpoint = false;\n /** @availableWhen type==power && powerSetpoint!=undefined */\n @property({type: Number}) powerSetpointAtZeroDeadband = 0.1;\n /** @availableWhen type==power && powerSetpoint!=undefined */\n @property({type: Boolean}) powerSetpointOverride = false;\n /** @availableWhen type==power && powerSetpoint!=undefined */\n @property({type: Boolean, attribute: false}) autoAtPowerSetpoint = true;\n /** @availableWhen type==power && powerSetpoint!=undefined && autoAtPowerSetpoint==true */\n @property({type: Number}) autoAtPowerSetpointDeadband = 1;\n\n /**\n * Signed rpm in percent of the maximum: 0 at the top, positive clockwise,\n * ±100% = ±180°. Shown on the primary track.\n * @availableWhen type==pitch-rpm\n */\n @property({type: Number}) rpm = 0;\n /** @availableWhen type==pitch-rpm */\n @property({type: Number}) rpmSetpoint: number | undefined;\n /** @availableWhen type==pitch-rpm && rpmSetpoint!=undefined */\n @property({type: Number}) newRpmSetpoint: number | undefined;\n /** @availableWhen type==pitch-rpm && rpmSetpoint!=undefined && autoAtRpmSetpoint==false */\n @property({type: Boolean}) atRpmSetpoint = false;\n /** @availableWhen type==pitch-rpm && rpmSetpoint!=undefined */\n @property({type: Number}) rpmSetpointAtZeroDeadband = 0.1;\n /** @availableWhen type==pitch-rpm && rpmSetpoint!=undefined */\n @property({type: Boolean}) rpmSetpointOverride = false;\n /** @availableWhen type==pitch-rpm && rpmSetpoint!=undefined */\n @property({type: Boolean, attribute: false}) autoAtRpmSetpoint = true;\n /** @availableWhen type==pitch-rpm && rpmSetpoint!=undefined && autoAtRpmSetpoint==true */\n @property({type: Number}) autoAtRpmSetpointDeadband = 1;\n\n /**\n * Signed pitch in percent: 0 at the top, positive clockwise, ±100% = ±180°.\n * Shown as the thin secondary arc.\n * @availableWhen type==pitch-rpm\n */\n @property({type: Number}) pitch = 0;\n\n /** @availableWhen powerSetpoint!=undefined || rpmSetpoint!=undefined */\n @property({type: Boolean}) touching = false;\n /** @availableWhen powerSetpoint!=undefined || rpmSetpoint!=undefined */\n @property({type: Boolean}) animateSetpoint = false;\n\n @property({type: String}) state: InstrumentState = InstrumentState.active;\n @property({type: String}) priority: Priority = Priority.regular;\n /**\n * Loading progress in percent, shown as an arc on the outer ring.\n * @availableWhen state==loading\n */\n @property({type: Number}) loading = 0;\n\n /**\n * Interval (in degrees) for primary tickmarks.\n * When undefined or <= 0, no primary tickmarks are shown (only the zero line).\n */\n @property({type: Number}) primaryTickmarkInterval: number | undefined = 90;\n /**\n * Interval (in degrees) for secondary tickmarks.\n * When undefined or <= 0, no secondary tickmarks are shown.\n */\n @property({type: Number}) secondaryTickmarkInterval: number | undefined =\n undefined;\n /**\n * Interval (in degrees) for tertiary tickmarks.\n * When undefined or <= 0, no tertiary tickmarks are shown.\n */\n @property({type: Number}) tertiaryTickmarkInterval: number | undefined =\n undefined;\n @property({type: Boolean}) showLabels = false;\n @property({type: Boolean}) tickmarksInside = false;\n @property({type: String}) tickmarkStyle: TickmarkStyle =\n TickmarkStyle.regular;\n @property({type: Boolean, attribute: false}) hasLabelSpacer = true;\n\n @property({type: String}) propeller: PropellerImage =\n PropellerImage.fourBlade;\n\n /**\n * Outer-ring diameter in CSS pixels. When set, the instrument renders at a\n * fixed intrinsic size derived from the ring, arc shape and label reserve —\n * so instruments sharing the same value have identical ring circumference\n * regardless of label width or arc extent (like obc-donut-chart's\n * fixedHeight). When unset (default), the instrument fills its container.\n */\n @property({type: Number, attribute: 'face-diameter'})\n faceDiameter: number | undefined;\n\n private _powerSp = new SetpointBundle({\n defaultDeadband: 1,\n defaultZeroDeadband: 0.1,\n onAnimationEnd: () => this.requestUpdate(),\n });\n private _rpmSp = new SetpointBundle({\n defaultDeadband: 1,\n defaultZeroDeadband: 0.1,\n onAnimationEnd: () => this.requestUpdate(),\n });\n\n private _frame: RadialFrame | undefined;\n private _hostSizePinned = false;\n private _resizeController = new ResizeController(this, {});\n\n override firstUpdated(changed: PropertyValues): void {\n super.firstUpdated(changed);\n observeInnerBox(this._resizeController, this.renderRoot);\n }\n\n override willUpdate(changed: PropertyValues): void {\n super.willUpdate(changed);\n this._powerSp.sync({\n setpoint: this.powerSetpoint,\n newSetpoint: this.newPowerSetpoint,\n atSetpoint: this.atPowerSetpoint,\n touching: this.touching,\n autoAtSetpoint: this.autoAtPowerSetpoint,\n autoAtSetpointDeadband: this.autoAtPowerSetpointDeadband,\n setpointAtZeroDeadband: this.powerSetpointAtZeroDeadband,\n setpointOverride: this.powerSetpointOverride,\n animateSetpoint: this.animateSetpoint,\n });\n this._rpmSp.sync({\n setpoint: this.rpmSetpoint,\n newSetpoint: this.newRpmSetpoint,\n atSetpoint: this.atRpmSetpoint,\n touching: this.touching,\n autoAtSetpoint: this.autoAtRpmSetpoint,\n autoAtSetpointDeadband: this.autoAtRpmSetpointDeadband,\n setpointAtZeroDeadband: this.rpmSetpointAtZeroDeadband,\n setpointOverride: this.rpmSetpointOverride,\n animateSetpoint: this.animateSetpoint,\n });\n }\n\n private get isPitchRpm(): boolean {\n return this.type === TopViewPropulsionType.pitchRpm;\n }\n\n private get primaryValue(): number {\n return this.isPitchRpm ? this.rpm : this.power;\n }\n\n private get primarySp(): SetpointBundle {\n return this.isPitchRpm ? this._rpmSp : this._powerSp;\n }\n\n private get primarySetpoint(): number | undefined {\n return this.isPitchRpm ? this.rpmSetpoint : this.powerSetpoint;\n }\n\n private get primaryNewSetpoint(): number | undefined {\n return this.isPitchRpm ? this.newRpmSetpoint : this.newPowerSetpoint;\n }\n\n private get primaryZeroDeadband(): number {\n return this.isPitchRpm\n ? this.rpmSetpointAtZeroDeadband\n : this.powerSetpointAtZeroDeadband;\n }\n\n private get primarySetpointOverride(): boolean {\n return this.isPitchRpm\n ? this.rpmSetpointOverride\n : this.powerSetpointOverride;\n }\n\n override updated(changed: PropertyValues): void {\n super.updated(changed);\n this._hostSizePinned = applyPinnedHostSize(\n this,\n this._frame,\n this._hostSizePinned\n );\n }\n\n override disconnectedCallback(): void {\n super.disconnectedCallback();\n this._powerSp.dispose();\n this._rpmSp.dispose();\n }\n\n private get isActive(): boolean {\n return (\n this.state !== InstrumentState.loading &&\n this.state !== InstrumentState.off\n );\n }\n\n private get isEnhanced(): boolean {\n return this.priority === Priority.enhanced;\n }\n\n private getTickmarks(): Tickmark[] {\n const tickmarks: Tickmark[] = [];\n const skipAngles: number[] = [];\n\n const labelText = (angle: number): string | undefined => {\n if (!this.showLabels) return undefined;\n return angle <= 180 ? `${angle}` : `${angle - 360}`;\n };\n\n tickmarks.push({\n angle: 0,\n type: TickmarkType.zeroLineThick,\n text: this.showLabels ? '0' : undefined,\n color:\n this.isActive && this.isEnhanced\n ? 'var(--instrument-enhanced-tertiary-color)'\n : undefined,\n });\n skipAngles.push(0);\n\n const addInterval = (\n interval: number | undefined,\n type: TickmarkType,\n withLabels = false\n ) => {\n if (interval === undefined || interval <= 0 || !Number.isFinite(interval))\n return;\n for (let i = interval; i < 360; i += interval) {\n if (skipAngles.includes(i)) continue;\n tickmarks.push({\n angle: i,\n type,\n text: withLabels ? labelText(i) : undefined,\n });\n skipAngles.push(i);\n }\n };\n\n addInterval(this.primaryTickmarkInterval, TickmarkType.primary, true);\n addInterval(this.secondaryTickmarkInterval, TickmarkType.secondary);\n addInterval(this.tertiaryTickmarkInterval, TickmarkType.tertiary);\n\n return tickmarks;\n }\n\n private getBarAreas(): WatchBarArea[] {\n const areas: WatchBarArea[] = [\n {\n startAngle: 0,\n endAngle: FULL_CIRCLE_END_ANGLE,\n fillColor: 'var(--instrument-frame-secondary-color)',\n },\n ];\n const valueAngle = percentToAngle(this.primaryValue);\n if (this.isActive && Math.abs(valueAngle) > 0.1) {\n areas.push({\n startAngle: Math.min(0, valueAngle),\n endAngle: Math.max(0, valueAngle),\n fillColor: this.isEnhanced\n ? 'var(--instrument-enhanced-tertiary-color)'\n : 'var(--instrument-regular-tertiary-color)',\n innerRadius: this.isPitchRpm ? PRIMARY_SUBBAND_INNER_RADIUS : undefined,\n });\n }\n return areas;\n }\n\n private getNeedles(): WatchNeedle[] {\n const fill = !this.isActive\n ? 'var(--instrument-frame-tertiary-color)'\n : this.isEnhanced\n ? 'var(--instrument-enhanced-secondary-color)'\n : 'var(--instrument-regular-secondary-color)';\n const stroke = !this.isActive\n ? 'var(--border-silhouette-color)'\n : this.isEnhanced\n ? 'var(--instrument-enhanced-tertiary-color)'\n : 'var(--instrument-regular-tertiary-color)';\n return [\n {\n angle: percentToAngle(this.primaryValue),\n fillColor: fill,\n strokeColor: stroke,\n length: this.isPitchRpm ? PRIMARY_SUBBAND_NEEDLE_LENGTH : undefined,\n },\n ];\n }\n\n private get secondaryColor(): string {\n if (!this.isActive) {\n return 'var(--instrument-frame-tertiary-color)';\n }\n return this.isEnhanced\n ? 'var(--instrument-enhanced-secondary-color)'\n : 'var(--instrument-regular-secondary-color)';\n }\n\n private renderSecondaryArc() {\n if (!this.isPitchRpm) {\n return nothing;\n }\n const divider = svg`<circle\n r=${LANE_DIVIDER_RADIUS}\n fill=\"none\"\n stroke=\"var(--instrument-frame-primary-color)\"\n stroke-width=${LANE_DIVIDER_WIDTH}\n ></circle>`;\n const pitchAngle = this.isActive ? percentToAngle(this.pitch) : 0;\n return svg`\n ${divider}\n ${renderSecondaryLine({\n originAngle: 0,\n endAngle: pitchAngle,\n color: this.secondaryColor,\n })}\n `;\n }\n\n private renderLoadingArc() {\n if (this.state !== InstrumentState.loading || this.loading <= 0) {\n return nothing;\n }\n const endAngle = percentToAngle(Math.abs(this.loading)) * 2;\n return svg`<path\n d=${arcPath(LOADING_ARC_RADIUS, 0, Math.min(endAngle, FULL_CIRCLE_END_ANGLE))}\n fill=\"none\"\n stroke=${\n this.isEnhanced\n ? 'var(--instrument-enhanced-secondary-color)'\n : 'var(--instrument-regular-secondary-color)'\n }\n stroke-width=\"8\"\n stroke-linecap=\"round\"\n ></path>`;\n }\n\n /**\n * Thin outline on the track band's inner edge, always shown per the\n * design's track face. Drawn on the overlay because the watch paints its\n * band bars over the ring circles, which would swallow a watch-side line.\n */\n private renderInnerRingLine() {\n return svg`<circle\n r=${BAND_INNER_RADIUS}\n fill=\"none\"\n stroke=\"var(--instrument-frame-tertiary-color)\"\n stroke-width=\"1\"\n vector-effect=\"non-scaling-stroke\"\n ></circle>`;\n }\n\n private renderPropeller() {\n return svg`<g transform=\"scale(${PROPELLER_SCALE}) translate(-80 -80)\">${\n propellerImages[this.propeller]\n }</g>`;\n }\n\n override render() {\n const tickmarks = this.getTickmarks();\n\n const frame = computeRadialFrame({\n basePadding: this.hasLabelSpacer ? 24 : 16,\n labelWidthPx:\n this.hasLabelSpacer && !this.tickmarksInside\n ? estimateLabelWidthPx(tickmarks.map((t) => t.text))\n : 0,\n containerPx: measureContainerPx(this),\n faceDiameter: this.faceDiameter,\n });\n this._frame = frame;\n const shownTickmarks = frame.labelsHidden\n ? tickmarks.map((t) => ({...t, text: undefined}))\n : tickmarks;\n\n const setpointAngle =\n this.primarySetpoint !== undefined\n ? percentToAngle(this.primarySetpoint)\n : undefined;\n const newSetpointAngle =\n this.primaryNewSetpoint !== undefined\n ? percentToAngle(this.primaryNewSetpoint)\n : undefined;\n\n return html`\n <div class=\"container\">\n <obc-watch\n .touching=${this.touching}\n .arcFrame=${frame}\n .watchCircleType=${WatchCircleType.double}\n .tickmarks=${shownTickmarks}\n .state=${this.state}\n .priority=${this.priority}\n .barAreas=${this.getBarAreas()}\n .needles=${this.getNeedles()}\n .angleSetpoint=${setpointAngle}\n .newAngleSetpoint=${newSetpointAngle}\n .atAngleSetpoint=${this.primarySp.computeAtSetpoint(\n this.primaryValue\n )}\n .angleSetpointAtZeroDeadband=${this.primaryZeroDeadband * 1.8}\n .setpointOverride=${this.primarySetpointOverride}\n .animateSetpoint=${this.animateSetpoint}\n .tickmarksInside=${this.tickmarksInside}\n .tickmarkStyle=${this.tickmarkStyle}\n ></obc-watch>\n <svg viewBox=${frame.viewBox} xmlns=\"http://www.w3.org/2000/svg\">\n ${this.renderInnerRingLine()} ${this.renderLoadingArc()}\n ${this.renderSecondaryArc()} ${this.renderPropeller()}\n </svg>\n </div>\n `;\n }\n\n static override styles = unsafeCSS(componentStyle);\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'obc-top-view-propulsion': ObcTopViewPropulsion;\n }\n}\n"],"names":["TopViewPropulsionType"],"mappings":"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"}
|
|
@@ -49,6 +49,14 @@ export declare const WIND_TRUE_BUCKETS: readonly [0, 1, 5, 10, 15, 20, 25, 30, 3
|
|
|
49
49
|
* a sub-1 calm icon).
|
|
50
50
|
*/
|
|
51
51
|
export declare const WIND_SHAFT_BUCKETS: readonly [0, 1, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, 100];
|
|
52
|
+
/**
|
|
53
|
+
* Radial overhang of the rendered (2×, 48-unit) wind icon box past the tip
|
|
54
|
+
* anchor toward the watch center: the glyph tip sits at y=22.4453 of the
|
|
55
|
+
* 24-unit box, so the scaled box extends `(24 − 22.4453) × 2 ≈ 3.11` units
|
|
56
|
+
* inside the anchor radius. Add it to a desired box inner-edge radius to get
|
|
57
|
+
* the `windSymbolRadius` that makes the box start exactly there.
|
|
58
|
+
*/
|
|
59
|
+
export declare const WIND_ICON_TIP_TO_BOX_INNER: number;
|
|
52
60
|
/**
|
|
53
61
|
* Snap a wind speed in **knots** to the nearest available icon bucket.
|
|
54
62
|
*
|