@oicl/openbridge-webcomponents 2.0.0-next.56 → 2.0.0-next.57
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 +395 -123
- package/bundle/openbridge-webcomponents.bundle.js.map +1 -1
- package/custom-elements.json +284 -2
- package/dist/navigation-instruments/compass-sector/compass-sector.css.js +12 -0
- package/dist/navigation-instruments/compass-sector/compass-sector.css.js.map +1 -1
- package/dist/navigation-instruments/compass-sector/compass-sector.d.ts +23 -0
- package/dist/navigation-instruments/compass-sector/compass-sector.d.ts.map +1 -1
- package/dist/navigation-instruments/compass-sector/compass-sector.js +47 -0
- package/dist/navigation-instruments/compass-sector/compass-sector.js.map +1 -1
- package/dist/navigation-instruments/pitch/pitch.d.ts +37 -0
- package/dist/navigation-instruments/pitch/pitch.d.ts.map +1 -1
- package/dist/navigation-instruments/pitch/pitch.js +130 -62
- package/dist/navigation-instruments/pitch/pitch.js.map +1 -1
- package/dist/navigation-instruments/pitch-roll/pitch-roll.d.ts +7 -0
- package/dist/navigation-instruments/pitch-roll/pitch-roll.d.ts.map +1 -1
- package/dist/navigation-instruments/pitch-roll/pitch-roll.js +58 -2
- package/dist/navigation-instruments/pitch-roll/pitch-roll.js.map +1 -1
- package/dist/navigation-instruments/roll/roll.d.ts +37 -0
- package/dist/navigation-instruments/roll/roll.d.ts.map +1 -1
- package/dist/navigation-instruments/roll/roll.js +119 -63
- package/dist/navigation-instruments/roll/roll.js.map +1 -1
- package/dist/navigation-instruments/rot-sector/rot-sector.d.ts +15 -0
- package/dist/navigation-instruments/rot-sector/rot-sector.d.ts.map +1 -1
- package/dist/navigation-instruments/rot-sector/rot-sector.js +53 -1
- package/dist/navigation-instruments/rot-sector/rot-sector.js.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"compass-sector.js","sources":["../../../src/navigation-instruments/compass-sector/compass-sector.ts"],"sourcesContent":["import {LitElement, PropertyValues, html, svg, unsafeCSS, nothing} from 'lit';\nimport {property} from 'lit/decorators.js';\nimport componentStyle from './compass-sector.css?inline';\nimport '../watch/watch.js';\nimport {Tickmark, TickmarkType, TickmarkStyle} from '../watch/tickmark.js';\nimport {arrow, ArrowStyle} from '../compass/arrow.js';\nimport {AdviceState, AngleAdvice, AngleAdviceRaw} from '../watch/advice.js';\nimport {\n WatchCircleType,\n WatchArea,\n OUTER_RING_RADIUS,\n innerRingRadiusFor,\n RotType,\n RotPosition,\n} from '../watch/watch.js';\nimport {SetpointBundle} from '../../svghelpers/setpoint-bundle.js';\nimport {\n computeZoomToFitArcFrame,\n type ZoomToFitArcFrame,\n} from '../../svghelpers/arc-frame.js';\nimport {ROT_ZERO_DEADBAND_DEG} from '../rate-of-turn/rot-renderer.js';\nimport {customElement} from '../../decorator.js';\nimport {InstrumentState, Priority} from '../types.js';\nexport {RotType, RotPosition};\n\nexport enum CompassSectorPriorityElement {\n hdg = 'hdg',\n cog = 'cog',\n rot = 'rot',\n}\n\nconst PADDING = 72;\nconst WATCH_TYPE = WatchCircleType.triple;\nconst INNER_RADIUS = innerRingRadiusFor(WATCH_TYPE);\n/** Half of the fixed 120° arc on the watch face. */\nconst ARC_HALF_EXTENT = 60;\nconst SCALE_INNER_RADIUS = innerRingRadiusFor(WatchCircleType.single);\n\ninterface TickDensity {\n mainInterval: number;\n primaryInterval: number;\n secondaryInterval: number | undefined;\n}\n\nfunction tickDensityForFOV(fov: number): TickDensity {\n if (fov <= 30) {\n return {mainInterval: 10, primaryInterval: 5, secondaryInterval: 1};\n } else if (fov <= 60) {\n return {mainInterval: 10, primaryInterval: 5, secondaryInterval: undefined};\n } else if (fov <= 120) {\n return {mainInterval: 30, primaryInterval: 10, secondaryInterval: 5};\n } else {\n return {mainInterval: 90, primaryInterval: 30, secondaryInterval: 10};\n }\n}\n\nfunction normalizeAngle(a: number): number {\n return ((a % 360) + 360) % 360;\n}\n\n/**\n * `<obc-compass-sector>` — Curved compass strip that auto‑scales to keep HDG and COG visible.\n *\n * Renders a fixed 120° arc of a triple‑ring compass face. The visible\n * compass range (field of view) adjusts automatically so that both the\n * heading (HDG) and course‑over‑ground (COG) arrows are always in view.\n * This is the radial equivalent of `<obc-compass-flat>`: the arc shape\n * never changes — only the scale (compass‑degrees per arc‑degree) changes.\n *\n * ## Features\n *\n * - **Fixed 120° arc**: The watch face is always a 120° sector (±60° from\n * center), identical in shape to `<obc-rot-sector>`.\n * - **FOV auto‑scaling**: The field of view widens when the HDG–COG\n * angular difference grows, compressing more compass degrees into the\n * fixed arc. Tickmark density adjusts automatically.\n * - **HDG / COG arrows**: Solid (HDG) arrow is always at the arc center.\n * Hollow (COG) arrow is positioned proportionally within the arc.\n * - **North arrow**: A gray triangle in the outer scale band indicates\n * north when it falls within the visible FOV.\n * - **Heading setpoint**: Optional setpoint marker with auto at‑setpoint\n * detection and confirm animation, positioned at the mapped arc angle.\n * - **Advice zones**: Pass `headingAdvices` to render caution/alert arcs,\n * mapped into the scaled arc.\n * - **Rate of turn**: Animated ROT indicator (dots or bar) spanning from\n * HDG to the mapped COG position, clipped to the arc.\n * - **Zoom to fit**: When `zoomToFitArc` is `true`, the fixed 120° arc is\n * enlarged to fill the available space.\n *\n * ## Usage Guidelines\n *\n * - Set `heading` and `courseOverGround` to sensor values in degrees.\n * - Adjust `minFOV` to control the minimum zoom level (default 30°).\n * - Enable `zoomToFitArc` to enlarge the arc to fill the viewport.\n * - For a full‑circle compass, use `<obc-compass>` instead.\n *\n * @fires None\n */\n@customElement('obc-compass-sector')\nexport class ObcCompassSector extends LitElement {\n @property({type: Number}) heading = 0;\n @property({type: Number}) courseOverGround = 0;\n\n @property({type: Number}) headingSetpoint: number | null = null;\n @property({type: Number}) newHeadingSetpoint: number | undefined;\n @property({type: Boolean}) atHeadingSetpoint: boolean = false;\n @property({type: Number}) headingSetpointAtZeroDeadband: number = 0.5;\n @property({type: Boolean}) headingSetpointOverride: boolean = false;\n @property({type: Boolean, attribute: false}) autoAtHeadingSetpoint = true;\n @property({type: Number}) autoAtHeadingSetpointDeadband: number = 2;\n @property({type: Boolean}) animateSetpoint: boolean = false;\n @property({type: Boolean}) touching: boolean = false;\n @property({type: Array, attribute: false}) headingAdvices: AngleAdvice[] = [];\n\n @property({type: Number}) minFOV: number = 30;\n\n @property({type: String}) rotType: RotType | undefined;\n @property({type: String}) rotPosition: RotPosition = RotPosition.innerCircle;\n /**\n * Measured rate of turn in degrees per minute (positive = starboard).\n * Drives both the bar extent and (after multiplication by\n * `rotDotAnimationFactor`) the spinning dot animation. When `undefined`,\n * falls back to the deprecated `rotationsPerMinute`.\n */\n @property({type: Number}) rateOfTurnDegreesPerMinute: number | undefined;\n /**\n * Visual amplification applied only to the spinning dot animation\n * (not to the bar extent). Default `18` keeps the legacy visual feel\n * (≈1 rpm at 20°/min).\n */\n @property({type: Number}) rotDotAnimationFactor: number = 18;\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 * Bar-extent reference value in **degrees per minute**. The bar fills the\n * full ±`ARC_HALF_EXTENT` arc when the measured ROT equals\n * ±`rotMaxValue`. Default `60` aligns with ES-TRIN 2025/1 Art. 3.02.\n *\n * Note: the unit changed from rotations per minute to degrees per minute\n * with the introduction of `rateOfTurnDegreesPerMinute`.\n */\n @property({type: Number}) rotMaxValue: number = 60;\n @property({type: Boolean}) rotPortStarboard: boolean = false;\n @property({type: Number}) rotAtZeroDeadband: number = ROT_ZERO_DEADBAND_DEG;\n\n @property({type: String}) state: InstrumentState = InstrumentState.active;\n @property({type: String}) priority: Priority = Priority.regular;\n @property({type: Array, attribute: false})\n priorityElements: CompassSectorPriorityElement[] = [\n CompassSectorPriorityElement.hdg,\n ];\n @property({type: Boolean}) tickmarksInside: boolean = false;\n @property({type: Boolean}) zoomToFitArc: boolean = false;\n\n private _headingSp = new SetpointBundle({\n angularWraparound: true,\n onAnimationEnd: () => this.requestUpdate(),\n });\n\n // Cached computed values — updated in willUpdate()\n private _halfFOV = 30;\n private _arcHalfExtent = ARC_HALF_EXTENT;\n private _scale = 1;\n private _radiusOffset = 0;\n private _cachedViewBox = '';\n private _cachedArcFrame: ZoomToFitArcFrame | undefined;\n private _cachedAreas: WatchArea[] = [];\n private _cachedTickmarks: Tickmark[] = [];\n private _cachedAdvices: AngleAdviceRaw[] = [];\n\n override willUpdate(changed: PropertyValues): void {\n super.willUpdate(changed);\n this._headingSp.sync({\n setpoint: this.headingSetpoint ?? undefined,\n newSetpoint: this.newHeadingSetpoint,\n atSetpoint: this.atHeadingSetpoint,\n touching: this.touching,\n autoAtSetpoint: this.autoAtHeadingSetpoint,\n autoAtSetpointDeadband: this.autoAtHeadingSetpointDeadband,\n setpointAtZeroDeadband: this.headingSetpointAtZeroDeadband,\n setpointOverride: this.headingSetpointOverride,\n animateSetpoint: this.animateSetpoint,\n });\n\n const arcInputsChanged =\n changed.has('heading') ||\n changed.has('courseOverGround') ||\n changed.has('minFOV') ||\n changed.has('zoomToFitArc');\n\n if (arcInputsChanged) {\n let diff = this.courseOverGround - this.heading;\n if (diff > 180) diff -= 360;\n else if (diff < -180) diff += 360;\n const minFov = Math.max(1, this.minFOV);\n const MARGIN = 15;\n\n if (this.zoomToFitArc) {\n const needed = Math.max(minFov, Math.abs(diff) + MARGIN);\n if (needed <= ARC_HALF_EXTENT) {\n this._halfFOV = needed;\n this._arcHalfExtent = needed;\n this._scale = 1;\n } else {\n this._halfFOV = needed;\n this._arcHalfExtent = ARC_HALF_EXTENT;\n this._scale = ARC_HALF_EXTENT / needed;\n }\n } else {\n this._halfFOV = Math.max(minFov, Math.abs(diff));\n this._arcHalfExtent = ARC_HALF_EXTENT;\n this._scale = ARC_HALF_EXTENT / this._halfFOV;\n }\n\n this._cachedAreas = [\n {\n startAngle: this.heading - this._arcHalfExtent,\n endAngle: this.heading + this._arcHalfExtent,\n roundInsideCut: true,\n roundOutsideCut: true,\n },\n ];\n\n this._computeViewBox();\n this._cachedTickmarks = this._buildTickmarks();\n }\n\n if (arcInputsChanged || changed.has('headingAdvices')) {\n this._cachedAdvices = this._buildAdvices();\n }\n }\n\n override disconnectedCallback(): void {\n super.disconnectedCallback();\n this._headingSp.dispose();\n }\n\n // ---------------------------------------------------------------------------\n // Angle mapping — maps compass degrees to arc positions\n // ---------------------------------------------------------------------------\n\n private _mapAngle(compassDeg: number): number {\n let diff = compassDeg - this.heading;\n if (diff > 180) diff -= 360;\n else if (diff < -180) diff += 360;\n return this.heading + diff * this._scale;\n }\n\n // ---------------------------------------------------------------------------\n // Areas — fixed 120° arc centered on heading (built in willUpdate)\n // ---------------------------------------------------------------------------\n\n // ---------------------------------------------------------------------------\n // Tickmarks — compass-degree labels at mapped arc positions\n // ---------------------------------------------------------------------------\n\n private _buildTickmarks(): Tickmark[] {\n const fov = this._halfFOV * 2;\n const {mainInterval, primaryInterval, secondaryInterval} =\n tickDensityForFOV(fov);\n const halfFov = this._halfFOV;\n const compassStart = this.heading - halfFov;\n const compassEnd = this.heading + halfFov;\n\n const tickmarks: Tickmark[] = [];\n const added = new Set<number>();\n\n const addTick = (\n arcAngle: number,\n type: TickmarkType,\n text?: string\n ): void => {\n const key = Math.round(arcAngle * 1000);\n if (added.has(key)) return;\n added.add(key);\n tickmarks.push({angle: arcAngle, type, text});\n };\n\n const step = secondaryInterval ?? primaryInterval;\n const firstTick = Math.ceil(compassStart / step) * step;\n\n for (\n let compassDeg = firstTick;\n compassDeg <= compassEnd;\n compassDeg += step\n ) {\n const norm = normalizeAngle(compassDeg);\n const arcAngle = this._mapAngle(compassDeg);\n const isMain = norm % mainInterval === 0;\n const isPrimary = norm % primaryInterval === 0;\n\n if (isMain) {\n addTick(arcAngle, TickmarkType.main, Math.round(norm).toString());\n } else if (isPrimary) {\n addTick(arcAngle, TickmarkType.primary);\n } else {\n addTick(arcAngle, TickmarkType.secondary);\n }\n }\n\n return tickmarks;\n }\n\n // ---------------------------------------------------------------------------\n // ViewBox\n // ---------------------------------------------------------------------------\n\n private _computeViewBox(): void {\n if (this.zoomToFitArc) {\n const targetSize = (176 + PADDING) * 2;\n const frame = computeZoomToFitArcFrame({\n areas: this._cachedAreas,\n outerRadius: OUTER_RING_RADIUS,\n innerRadius: INNER_RADIUS,\n extension: PADDING,\n targetSize,\n });\n this._radiusOffset = frame.radiusOffset;\n this._cachedViewBox = frame.viewBox;\n this._cachedArcFrame = frame;\n } else {\n this._radiusOffset = 0;\n const width = (176 + PADDING) * 2;\n this._cachedViewBox = `-${width / 2} -${width / 2} ${width} ${width}`;\n this._cachedArcFrame = undefined;\n }\n }\n\n // ---------------------------------------------------------------------------\n // North arrow — rendered in overlay at mapped 0° position\n // ---------------------------------------------------------------------------\n\n private _renderNorthArrow(rOff: number) {\n let northOffset = -this.heading;\n if (northOffset > 180) northOffset -= 360;\n else if (northOffset < -180) northOffset += 360;\n if (Math.abs(northOffset) > this._halfFOV) return nothing;\n\n const northArcAngle = this._mapAngle(0);\n const radius = OUTER_RING_RADIUS + rOff;\n return svg`\n <g transform=\"rotate(${northArcAngle}) translate(0, ${-radius})\">\n <path fill-rule=\"evenodd\" clip-rule=\"evenodd\"\n d=\"M-17.8457 24.984 0 0 17.8458 24.984C11.9868 24.3338 6.0324 24 0 24-6.0323 24-11.9867 24.3338-17.8457 24.984Z\"\n fill=\"var(--instrument-frame-tertiary-color)\"/>\n </g>\n `;\n }\n\n // ---------------------------------------------------------------------------\n // Priority & advice helpers\n // ---------------------------------------------------------------------------\n\n private _angleInRange(value: number, min: number, max: number): boolean {\n const v = normalizeAngle(value);\n const start = normalizeAngle(min);\n const end = normalizeAngle(max);\n return start <= end ? v >= start && v <= end : v >= start || v <= end;\n }\n\n private _buildAdvices(): AngleAdviceRaw[] {\n return this.headingAdvices.map(({minAngle, maxAngle, hinted, type}) => {\n const state = this._angleInRange(this.heading, minAngle, maxAngle)\n ? AdviceState.triggered\n : hinted\n ? AdviceState.hinted\n : AdviceState.regular;\n return {\n minAngle: this._mapAngle(minAngle),\n maxAngle: this._mapAngle(maxAngle),\n type,\n state,\n };\n });\n }\n\n private get _effectiveRotDegPerMin(): number {\n return this.rateOfTurnDegreesPerMinute ?? this.rotationsPerMinute;\n }\n\n private get _rotEndAngle(): number {\n const maxVal = this.rotMaxValue || 1;\n const barCompassDeg =\n (this._effectiveRotDegPerMin / maxVal) * ARC_HALF_EXTENT;\n return this._mapAngle(this.heading + barCompassDeg);\n }\n\n private priorityFor(element: CompassSectorPriorityElement): Priority {\n const selected = Array.isArray(this.priorityElements)\n ? this.priorityElements\n : [];\n return selected.includes(element) ? this.priority : Priority.regular;\n }\n\n // ---------------------------------------------------------------------------\n // Render\n // ---------------------------------------------------------------------------\n\n override render() {\n const rotation = -this.heading;\n const viewBox = this._cachedViewBox;\n const rOff = this._radiusOffset;\n\n const mappedCOG = this._mapAngle(this.courseOverGround);\n const mappedSetpoint =\n this.headingSetpoint != null\n ? this._mapAngle(this.headingSetpoint)\n : undefined;\n const mappedNewSetpoint =\n this.newHeadingSetpoint != null\n ? this._mapAngle(this.newHeadingSetpoint)\n : undefined;\n\n return html`\n <div class=\"container\">\n <obc-watch\n .touching=${this.touching}\n .padding=${PADDING}\n .advices=${this._cachedAdvices}\n .tickmarks=${this._cachedTickmarks}\n .tickmarkStyle=${TickmarkStyle.regular}\n .tickmarksInside=${this.tickmarksInside}\n .state=${this.state}\n .watchCircleType=${WATCH_TYPE}\n .northArrow=${false}\n .areas=${this._cachedAreas}\n .arcFrame=${this._cachedArcFrame}\n .zoomToFitArc=${this.zoomToFitArc}\n .tickFadeAngle=${this._arcHalfExtent * 0.2}\n .rotation=${rotation}\n .angleSetpoint=${mappedSetpoint}\n .newAngleSetpoint=${mappedNewSetpoint}\n .atAngleSetpoint=${this._headingSp.computeAtSetpoint(this.heading)}\n .angleSetpointAtZeroDeadband=${this.headingSetpointAtZeroDeadband}\n .setpointOverride=${this.headingSetpointOverride}\n .priority=${this.priority}\n .animateSetpoint=${this.animateSetpoint}\n .rotType=${this.rotType}\n .rotPosition=${this.rotPosition}\n .rotStartAngle=${this.heading}\n .rotEndAngle=${this._rotEndAngle}\n .rotPriority=${this.priorityFor(CompassSectorPriorityElement.rot)}\n .rotPortStarboard=${this.rotPortStarboard}\n .rotAtZeroDeadband=${this.rotAtZeroDeadband}\n .rateOfTurnDegreesPerMinute=${this.rateOfTurnDegreesPerMinute}\n .rotDotAnimationFactor=${this.rotDotAnimationFactor}\n .rotationsPerMinute=${this.rotationsPerMinute}\n >\n </obc-watch>\n <svg viewBox=\"${viewBox}\" transform=\"rotate(${rotation})\">\n <g transform=\"rotate(${this.heading})\">\n <line\n x1=\"0\"\n y1=\"${-(SCALE_INNER_RADIUS + rOff)}\"\n x2=\"0\"\n y2=\"${-(INNER_RADIUS + rOff)}\"\n stroke=\"var(--instrument-frame-tertiary-color)\"\n stroke-width=\"1\"\n vector-effect=\"non-scaling-stroke\"\n />\n </g>\n ${this._renderNorthArrow(rOff)}\n ${arrow(\n ArrowStyle.HDG,\n this.heading,\n this.priorityFor(CompassSectorPriorityElement.hdg),\n rOff\n )}\n ${arrow(\n ArrowStyle.COG,\n mappedCOG,\n this.priorityFor(CompassSectorPriorityElement.cog),\n rOff\n )}\n </svg>\n </div>\n `;\n }\n\n static override styles = unsafeCSS(componentStyle);\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'obc-compass-sector': ObcCompassSector;\n }\n}\n"],"names":["CompassSectorPriorityElement"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"compass-sector.js","sources":["../../../src/navigation-instruments/compass-sector/compass-sector.ts"],"sourcesContent":["import {LitElement, PropertyValues, html, svg, unsafeCSS, nothing} from 'lit';\nimport {property} from 'lit/decorators.js';\nimport componentStyle from './compass-sector.css?inline';\nimport '../watch/watch.js';\nimport '../readout/readout.js';\nimport {ReadoutDirection, ReadoutVariant} from '../readout/readout.js';\nimport {Tickmark, TickmarkType, TickmarkStyle} from '../watch/tickmark.js';\nimport {arrow, ArrowStyle} from '../compass/arrow.js';\nimport {AdviceState, AngleAdvice, AngleAdviceRaw} from '../watch/advice.js';\nimport {\n WatchCircleType,\n WatchArea,\n OUTER_RING_RADIUS,\n innerRingRadiusFor,\n RotType,\n RotPosition,\n} from '../watch/watch.js';\nimport {SetpointBundle} from '../../svghelpers/setpoint-bundle.js';\nimport {\n computeZoomToFitArcFrame,\n type ZoomToFitArcFrame,\n} from '../../svghelpers/arc-frame.js';\nimport {ROT_ZERO_DEADBAND_DEG} from '../rate-of-turn/rot-renderer.js';\nimport {customElement} from '../../decorator.js';\nimport {InstrumentState, Priority} from '../types.js';\nexport {RotType, RotPosition};\n\nexport enum CompassSectorPriorityElement {\n hdg = 'hdg',\n cog = 'cog',\n rot = 'rot',\n}\n\nconst PADDING = 72;\nconst WATCH_TYPE = WatchCircleType.triple;\nconst INNER_RADIUS = innerRingRadiusFor(WATCH_TYPE);\n/** Half of the fixed 120° arc on the watch face. */\nconst ARC_HALF_EXTENT = 60;\nconst SCALE_INNER_RADIUS = innerRingRadiusFor(WatchCircleType.single);\n\ninterface TickDensity {\n mainInterval: number;\n primaryInterval: number;\n secondaryInterval: number | undefined;\n}\n\nfunction tickDensityForFOV(fov: number): TickDensity {\n if (fov <= 30) {\n return {mainInterval: 10, primaryInterval: 5, secondaryInterval: 1};\n } else if (fov <= 60) {\n return {mainInterval: 10, primaryInterval: 5, secondaryInterval: undefined};\n } else if (fov <= 120) {\n return {mainInterval: 30, primaryInterval: 10, secondaryInterval: 5};\n } else {\n return {mainInterval: 90, primaryInterval: 30, secondaryInterval: 10};\n }\n}\n\nfunction normalizeAngle(a: number): number {\n return ((a % 360) + 360) % 360;\n}\n\n/**\n * `<obc-compass-sector>` — Curved compass strip that auto‑scales to keep HDG and COG visible.\n *\n * Renders a fixed 120° arc of a triple‑ring compass face. The visible\n * compass range (field of view) adjusts automatically so that both the\n * heading (HDG) and course‑over‑ground (COG) arrows are always in view.\n * This is the radial equivalent of `<obc-compass-flat>`: the arc shape\n * never changes — only the scale (compass‑degrees per arc‑degree) changes.\n *\n * ## Features\n *\n * - **Fixed 120° arc**: The watch face is always a 120° sector (±60° from\n * center), identical in shape to `<obc-rot-sector>`.\n * - **FOV auto‑scaling**: The field of view widens when the HDG–COG\n * angular difference grows, compressing more compass degrees into the\n * fixed arc. Tickmark density adjusts automatically.\n * - **HDG / COG arrows**: Solid (HDG) arrow is always at the arc center.\n * Hollow (COG) arrow is positioned proportionally within the arc.\n * - **North arrow**: A gray triangle in the outer scale band indicates\n * north when it falls within the visible FOV.\n * - **Heading setpoint**: Optional setpoint marker with auto at‑setpoint\n * detection and confirm animation, positioned at the mapped arc angle.\n * - **Advice zones**: Pass `headingAdvices` to render caution/alert arcs,\n * mapped into the scaled arc.\n * - **Rate of turn**: Animated ROT indicator (dots or bar) spanning from\n * HDG to the mapped COG position, clipped to the arc.\n * - **Zoom to fit**: When `zoomToFitArc` is `true`, the fixed 120° arc is\n * enlarged to fill the available space.\n *\n * ## Usage Guidelines\n *\n * - Set `heading` and `courseOverGround` to sensor values in degrees.\n * - Adjust `minFOV` to control the minimum zoom level (default 30°).\n * - Enable `zoomToFitArc` to enlarge the arc to fill the viewport.\n * - For a full‑circle compass, use `<obc-compass>` instead.\n *\n * @fires None\n */\n@customElement('obc-compass-sector')\nexport class ObcCompassSector extends LitElement {\n @property({type: Number}) heading = 0;\n @property({type: Number}) courseOverGround = 0;\n\n @property({type: Number}) headingSetpoint: number | null = null;\n @property({type: Number}) newHeadingSetpoint: number | undefined;\n @property({type: Boolean}) atHeadingSetpoint: boolean = false;\n @property({type: Number}) headingSetpointAtZeroDeadband: number = 0.5;\n @property({type: Boolean}) headingSetpointOverride: boolean = false;\n @property({type: Boolean, attribute: false}) autoAtHeadingSetpoint = true;\n @property({type: Number}) autoAtHeadingSetpointDeadband: number = 2;\n @property({type: Boolean}) animateSetpoint: boolean = false;\n @property({type: Boolean}) touching: boolean = false;\n @property({type: Array, attribute: false}) headingAdvices: AngleAdvice[] = [];\n\n @property({type: Number}) minFOV: number = 30;\n\n @property({type: String}) rotType: RotType | undefined;\n @property({type: String}) rotPosition: RotPosition = RotPosition.innerCircle;\n /**\n * Measured rate of turn in degrees per minute (positive = starboard).\n * Drives both the bar extent and (after multiplication by\n * `rotDotAnimationFactor`) the spinning dot animation. When `undefined`,\n * falls back to the deprecated `rotationsPerMinute`.\n */\n @property({type: Number}) rateOfTurnDegreesPerMinute: number | undefined;\n /**\n * Visual amplification applied only to the spinning dot animation\n * (not to the bar extent). Default `18` keeps the legacy visual feel\n * (≈1 rpm at 20°/min).\n */\n @property({type: Number}) rotDotAnimationFactor: number = 18;\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 * Bar-extent reference value in **degrees per minute**. The bar fills the\n * full ±`ARC_HALF_EXTENT` arc when the measured ROT equals\n * ±`rotMaxValue`. Default `60` aligns with ES-TRIN 2025/1 Art. 3.02.\n *\n * Note: the unit changed from rotations per minute to degrees per minute\n * with the introduction of `rateOfTurnDegreesPerMinute`.\n */\n @property({type: Number}) rotMaxValue: number = 60;\n @property({type: Boolean}) rotPortStarboard: boolean = false;\n @property({type: Number}) rotAtZeroDeadband: number = ROT_ZERO_DEADBAND_DEG;\n\n @property({type: String}) state: InstrumentState = InstrumentState.active;\n @property({type: String}) priority: Priority = Priority.regular;\n @property({type: Array, attribute: false})\n priorityElements: CompassSectorPriorityElement[] = [\n CompassSectorPriorityElement.hdg,\n ];\n @property({type: Boolean}) tickmarksInside: boolean = false;\n @property({type: Boolean}) zoomToFitArc: boolean = false;\n /**\n * When `true`, shows a centered `<obc-readout>` under the arc displaying the\n * heading (label `HDG`, unit `DEG`). The value color follows the HDG entry in\n * `priorityElements`, matching the HDG arrow.\n */\n @property({type: Boolean}) hasReadout: boolean = false;\n\n private _headingSp = new SetpointBundle({\n angularWraparound: true,\n onAnimationEnd: () => this.requestUpdate(),\n });\n\n // Cached computed values — updated in willUpdate()\n private _halfFOV = 30;\n private _arcHalfExtent = ARC_HALF_EXTENT;\n private _scale = 1;\n private _radiusOffset = 0;\n private _cachedViewBox = '';\n private _cachedArcFrame: ZoomToFitArcFrame | undefined;\n private _cachedAreas: WatchArea[] = [];\n private _cachedTickmarks: Tickmark[] = [];\n private _cachedAdvices: AngleAdviceRaw[] = [];\n\n override willUpdate(changed: PropertyValues): void {\n super.willUpdate(changed);\n this._headingSp.sync({\n setpoint: this.headingSetpoint ?? undefined,\n newSetpoint: this.newHeadingSetpoint,\n atSetpoint: this.atHeadingSetpoint,\n touching: this.touching,\n autoAtSetpoint: this.autoAtHeadingSetpoint,\n autoAtSetpointDeadband: this.autoAtHeadingSetpointDeadband,\n setpointAtZeroDeadband: this.headingSetpointAtZeroDeadband,\n setpointOverride: this.headingSetpointOverride,\n animateSetpoint: this.animateSetpoint,\n });\n\n const arcInputsChanged =\n changed.has('heading') ||\n changed.has('courseOverGround') ||\n changed.has('minFOV') ||\n changed.has('zoomToFitArc');\n\n if (arcInputsChanged) {\n let diff = this.courseOverGround - this.heading;\n if (diff > 180) diff -= 360;\n else if (diff < -180) diff += 360;\n const minFov = Math.max(1, this.minFOV);\n const MARGIN = 15;\n\n if (this.zoomToFitArc) {\n const needed = Math.max(minFov, Math.abs(diff) + MARGIN);\n if (needed <= ARC_HALF_EXTENT) {\n this._halfFOV = needed;\n this._arcHalfExtent = needed;\n this._scale = 1;\n } else {\n this._halfFOV = needed;\n this._arcHalfExtent = ARC_HALF_EXTENT;\n this._scale = ARC_HALF_EXTENT / needed;\n }\n } else {\n this._halfFOV = Math.max(minFov, Math.abs(diff));\n this._arcHalfExtent = ARC_HALF_EXTENT;\n this._scale = ARC_HALF_EXTENT / this._halfFOV;\n }\n\n this._cachedAreas = [\n {\n startAngle: this.heading - this._arcHalfExtent,\n endAngle: this.heading + this._arcHalfExtent,\n roundInsideCut: true,\n roundOutsideCut: true,\n },\n ];\n\n this._computeViewBox();\n this._cachedTickmarks = this._buildTickmarks();\n }\n\n if (arcInputsChanged || changed.has('headingAdvices')) {\n this._cachedAdvices = this._buildAdvices();\n }\n }\n\n override disconnectedCallback(): void {\n super.disconnectedCallback();\n this._headingSp.dispose();\n }\n\n // ---------------------------------------------------------------------------\n // Angle mapping — maps compass degrees to arc positions\n // ---------------------------------------------------------------------------\n\n private _mapAngle(compassDeg: number): number {\n let diff = compassDeg - this.heading;\n if (diff > 180) diff -= 360;\n else if (diff < -180) diff += 360;\n return this.heading + diff * this._scale;\n }\n\n // ---------------------------------------------------------------------------\n // Areas — fixed 120° arc centered on heading (built in willUpdate)\n // ---------------------------------------------------------------------------\n\n // ---------------------------------------------------------------------------\n // Tickmarks — compass-degree labels at mapped arc positions\n // ---------------------------------------------------------------------------\n\n private _buildTickmarks(): Tickmark[] {\n const fov = this._halfFOV * 2;\n const {mainInterval, primaryInterval, secondaryInterval} =\n tickDensityForFOV(fov);\n const halfFov = this._halfFOV;\n const compassStart = this.heading - halfFov;\n const compassEnd = this.heading + halfFov;\n\n const tickmarks: Tickmark[] = [];\n const added = new Set<number>();\n\n const addTick = (\n arcAngle: number,\n type: TickmarkType,\n text?: string\n ): void => {\n const key = Math.round(arcAngle * 1000);\n if (added.has(key)) return;\n added.add(key);\n tickmarks.push({angle: arcAngle, type, text});\n };\n\n const step = secondaryInterval ?? primaryInterval;\n const firstTick = Math.ceil(compassStart / step) * step;\n\n for (\n let compassDeg = firstTick;\n compassDeg <= compassEnd;\n compassDeg += step\n ) {\n const norm = normalizeAngle(compassDeg);\n const arcAngle = this._mapAngle(compassDeg);\n const isMain = norm % mainInterval === 0;\n const isPrimary = norm % primaryInterval === 0;\n\n if (isMain) {\n addTick(arcAngle, TickmarkType.main, Math.round(norm).toString());\n } else if (isPrimary) {\n addTick(arcAngle, TickmarkType.primary);\n } else {\n addTick(arcAngle, TickmarkType.secondary);\n }\n }\n\n return tickmarks;\n }\n\n // ---------------------------------------------------------------------------\n // ViewBox\n // ---------------------------------------------------------------------------\n\n private _computeViewBox(): void {\n if (this.zoomToFitArc) {\n const targetSize = (176 + PADDING) * 2;\n const frame = computeZoomToFitArcFrame({\n areas: this._cachedAreas,\n outerRadius: OUTER_RING_RADIUS,\n innerRadius: INNER_RADIUS,\n extension: PADDING,\n targetSize,\n });\n this._radiusOffset = frame.radiusOffset;\n this._cachedViewBox = frame.viewBox;\n this._cachedArcFrame = frame;\n } else {\n this._radiusOffset = 0;\n const width = (176 + PADDING) * 2;\n this._cachedViewBox = `-${width / 2} -${width / 2} ${width} ${width}`;\n this._cachedArcFrame = undefined;\n }\n }\n\n // ---------------------------------------------------------------------------\n // North arrow — rendered in overlay at mapped 0° position\n // ---------------------------------------------------------------------------\n\n private _renderNorthArrow(rOff: number) {\n let northOffset = -this.heading;\n if (northOffset > 180) northOffset -= 360;\n else if (northOffset < -180) northOffset += 360;\n if (Math.abs(northOffset) > this._halfFOV) return nothing;\n\n const northArcAngle = this._mapAngle(0);\n const radius = OUTER_RING_RADIUS + rOff;\n return svg`\n <g transform=\"rotate(${northArcAngle}) translate(0, ${-radius})\">\n <path fill-rule=\"evenodd\" clip-rule=\"evenodd\"\n d=\"M-17.8457 24.984 0 0 17.8458 24.984C11.9868 24.3338 6.0324 24 0 24-6.0323 24-11.9867 24.3338-17.8457 24.984Z\"\n fill=\"var(--instrument-frame-tertiary-color)\"/>\n </g>\n `;\n }\n\n // ---------------------------------------------------------------------------\n // Priority & advice helpers\n // ---------------------------------------------------------------------------\n\n private _angleInRange(value: number, min: number, max: number): boolean {\n const v = normalizeAngle(value);\n const start = normalizeAngle(min);\n const end = normalizeAngle(max);\n return start <= end ? v >= start && v <= end : v >= start || v <= end;\n }\n\n private _buildAdvices(): AngleAdviceRaw[] {\n return this.headingAdvices.map(({minAngle, maxAngle, hinted, type}) => {\n const state = this._angleInRange(this.heading, minAngle, maxAngle)\n ? AdviceState.triggered\n : hinted\n ? AdviceState.hinted\n : AdviceState.regular;\n return {\n minAngle: this._mapAngle(minAngle),\n maxAngle: this._mapAngle(maxAngle),\n type,\n state,\n };\n });\n }\n\n private get _effectiveRotDegPerMin(): number {\n return this.rateOfTurnDegreesPerMinute ?? this.rotationsPerMinute;\n }\n\n private get _rotEndAngle(): number {\n const maxVal = this.rotMaxValue || 1;\n const barCompassDeg =\n (this._effectiveRotDegPerMin / maxVal) * ARC_HALF_EXTENT;\n return this._mapAngle(this.heading + barCompassDeg);\n }\n\n private priorityFor(element: CompassSectorPriorityElement): Priority {\n const selected = Array.isArray(this.priorityElements)\n ? this.priorityElements\n : [];\n return selected.includes(element) ? this.priority : Priority.regular;\n }\n\n /**\n * Vertical placement of the readout as a percentage of the host height.\n *\n * With `zoomToFitArc` the arc is reframed by `computeZoomToFitArcFrame`, whose\n * `radiusOffset`/`viewBox` depend on the arc's *absolute* orientation (which\n * cardinal axes its bounding box crosses), not just its bend. The arc itself\n * is always rotated back to the top, so it stays put on screen — but a\n * frame-derived offset would swing wildly as `heading` rotates the bbox around\n * the circle. So in zoom we use a fixed offset, which keeps the readout steady\n * under the (stationary) arc regardless of heading.\n *\n * Without zoom the viewBox is the fixed, origin-symmetric 120° framing, so the\n * geometry is orientation-independent: place the readout halfway down the inner\n * radius from the watch center toward the arc's inner edge.\n */\n private get _readoutTopPercent(): number {\n if (this.zoomToFitArc) {\n return 70;\n }\n const [, vy, , vh] = this._cachedViewBox.split(' ').map(Number);\n if (!vh || Number.isNaN(vy)) {\n return 50;\n }\n const anchorY = -INNER_RADIUS * 0.5;\n return Math.round(((anchorY - vy) / vh) * 1000) / 10;\n }\n\n // ---------------------------------------------------------------------------\n // Render\n // ---------------------------------------------------------------------------\n\n override render() {\n const rotation = -this.heading;\n const viewBox = this._cachedViewBox;\n const rOff = this._radiusOffset;\n\n const mappedCOG = this._mapAngle(this.courseOverGround);\n const mappedSetpoint =\n this.headingSetpoint != null\n ? this._mapAngle(this.headingSetpoint)\n : undefined;\n const mappedNewSetpoint =\n this.newHeadingSetpoint != null\n ? this._mapAngle(this.newHeadingSetpoint)\n : undefined;\n\n return html`\n <div class=\"container\">\n <obc-watch\n .touching=${this.touching}\n .padding=${PADDING}\n .advices=${this._cachedAdvices}\n .tickmarks=${this._cachedTickmarks}\n .tickmarkStyle=${TickmarkStyle.regular}\n .tickmarksInside=${this.tickmarksInside}\n .state=${this.state}\n .watchCircleType=${WATCH_TYPE}\n .northArrow=${false}\n .areas=${this._cachedAreas}\n .arcFrame=${this._cachedArcFrame}\n .zoomToFitArc=${this.zoomToFitArc}\n .tickFadeAngle=${this._arcHalfExtent * 0.2}\n .rotation=${rotation}\n .angleSetpoint=${mappedSetpoint}\n .newAngleSetpoint=${mappedNewSetpoint}\n .atAngleSetpoint=${this._headingSp.computeAtSetpoint(this.heading)}\n .angleSetpointAtZeroDeadband=${this.headingSetpointAtZeroDeadband}\n .setpointOverride=${this.headingSetpointOverride}\n .priority=${this.priority}\n .animateSetpoint=${this.animateSetpoint}\n .rotType=${this.rotType}\n .rotPosition=${this.rotPosition}\n .rotStartAngle=${this.heading}\n .rotEndAngle=${this._rotEndAngle}\n .rotPriority=${this.priorityFor(CompassSectorPriorityElement.rot)}\n .rotPortStarboard=${this.rotPortStarboard}\n .rotAtZeroDeadband=${this.rotAtZeroDeadband}\n .rateOfTurnDegreesPerMinute=${this.rateOfTurnDegreesPerMinute}\n .rotDotAnimationFactor=${this.rotDotAnimationFactor}\n .rotationsPerMinute=${this.rotationsPerMinute}\n >\n </obc-watch>\n <svg viewBox=\"${viewBox}\" transform=\"rotate(${rotation})\">\n <g transform=\"rotate(${this.heading})\">\n <line\n x1=\"0\"\n y1=\"${-(SCALE_INNER_RADIUS + rOff)}\"\n x2=\"0\"\n y2=\"${-(INNER_RADIUS + rOff)}\"\n stroke=\"var(--instrument-frame-tertiary-color)\"\n stroke-width=\"1\"\n vector-effect=\"non-scaling-stroke\"\n />\n </g>\n ${this._renderNorthArrow(rOff)}\n ${arrow(\n ArrowStyle.HDG,\n this.heading,\n this.priorityFor(CompassSectorPriorityElement.hdg),\n rOff\n )}\n ${arrow(\n ArrowStyle.COG,\n mappedCOG,\n this.priorityFor(CompassSectorPriorityElement.cog),\n rOff\n )}\n </svg>\n ${this.hasReadout\n ? html`<div class=\"readout\" style=\"top: ${this._readoutTopPercent}%\">\n <obc-readout\n .variant=${ReadoutVariant.enhanced}\n .direction=${ReadoutDirection.vertical}\n .hasSetpoint=${false}\n .hasAdvice=${false}\n .value=${this.heading}\n .fractionDigits=${0}\n .valuePriority=${this.priorityFor(\n CompassSectorPriorityElement.hdg\n )}\n label=\"HDG\"\n unit=\"DEG\"\n ></obc-readout>\n </div>`\n : nothing}\n </div>\n `;\n }\n\n static override styles = unsafeCSS(componentStyle);\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'obc-compass-sector': ObcCompassSector;\n }\n}\n"],"names":["CompassSectorPriorityElement"],"mappings":"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"}
|
|
@@ -1,6 +1,24 @@
|
|
|
1
1
|
import { LitElement } from 'lit';
|
|
2
2
|
import { VesselImage } from '../watch/watch.js';
|
|
3
|
+
import { Priority } from '../types.js';
|
|
3
4
|
import '../watch/watch.js';
|
|
5
|
+
import '../readout/readout.js';
|
|
6
|
+
export declare enum ObcPitchType {
|
|
7
|
+
/** Single arc scale on the right (default). */
|
|
8
|
+
singleScale = "single-scale",
|
|
9
|
+
/** Right scale duplicated to the opposite (left) arc as well. */
|
|
10
|
+
dualScale = "dual-scale"
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* `<obc-pitch>` — Pitch (trim) indicator with a side arc scale.
|
|
14
|
+
*
|
|
15
|
+
* Shows `pitch` against a watch arc centred on the right, with an average-pitch
|
|
16
|
+
* band and a rotating indicator. Supports an optional opposite-side scale
|
|
17
|
+
* (`dual-scale`), a centre readout (`hasReadout`), and a `regular`/`enhanced`
|
|
18
|
+
* palette.
|
|
19
|
+
*
|
|
20
|
+
* @element obc-pitch
|
|
21
|
+
*/
|
|
4
22
|
export declare class ObcPitch extends LitElement {
|
|
5
23
|
pitch: number;
|
|
6
24
|
minAvgPitch: number;
|
|
@@ -9,6 +27,22 @@ export declare class ObcPitch extends LitElement {
|
|
|
9
27
|
maxPitchAdvice: number | undefined;
|
|
10
28
|
triggerPitchAdvice: boolean;
|
|
11
29
|
zoomToFitArc: boolean;
|
|
30
|
+
/**
|
|
31
|
+
* When `true`, the centre shows an `<obc-readout>` with the pitch value
|
|
32
|
+
* (label `Pitch`, unit `DEG`) instead of the horizon line, rotating indicator
|
|
33
|
+
* and vessel. Default `false`.
|
|
34
|
+
*/
|
|
35
|
+
hasReadout: boolean;
|
|
36
|
+
/**
|
|
37
|
+
* `single-scale` shows one arc on the right (default); `dual-scale` also
|
|
38
|
+
* shows the scale on the opposite (left) arc (the indicator's opposite end).
|
|
39
|
+
*/
|
|
40
|
+
type: ObcPitchType;
|
|
41
|
+
/**
|
|
42
|
+
* Colour palette for the scale fill / indicator and the readout value:
|
|
43
|
+
* `regular` (default) or `enhanced`.
|
|
44
|
+
*/
|
|
45
|
+
priority: Priority;
|
|
12
46
|
/**
|
|
13
47
|
* Half-extent of the watch arc in degrees. The arc spans `90° ± arcAngle`
|
|
14
48
|
* and pitch values are placed at their true position within it. Default
|
|
@@ -22,7 +56,10 @@ export declare class ObcPitch extends LitElement {
|
|
|
22
56
|
*/
|
|
23
57
|
arcAngle: number;
|
|
24
58
|
private _arcFrame;
|
|
59
|
+
private get scaleFillColor();
|
|
60
|
+
private get indicatorColor();
|
|
25
61
|
render(): import('lit-html').TemplateResult<1>;
|
|
62
|
+
private renderScale;
|
|
26
63
|
private get advices();
|
|
27
64
|
static styles: import('lit').CSSResult;
|
|
28
65
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pitch.d.ts","sourceRoot":"","sources":["../../../src/navigation-instruments/pitch/pitch.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,UAAU,EAA0B,MAAM,KAAK,CAAC;AAExD,OAAO,mBAAmB,CAAC;AAC3B,OAAO,EACL,WAAW,
|
|
1
|
+
{"version":3,"file":"pitch.d.ts","sourceRoot":"","sources":["../../../src/navigation-instruments/pitch/pitch.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,UAAU,EAA0B,MAAM,KAAK,CAAC;AAExD,OAAO,mBAAmB,CAAC;AAC3B,OAAO,EACL,WAAW,EAOZ,MAAM,mBAAmB,CAAC;AAC3B,OAAO,uBAAuB,CAAC;AAE/B,OAAO,EAAC,QAAQ,EAAC,MAAM,aAAa,CAAC;AAerC,oBAAY,YAAY;IACtB,+CAA+C;IAC/C,WAAW,iBAAiB;IAC5B,iEAAiE;IACjE,SAAS,eAAe;CACzB;AAED;;;;;;;;;GASG;AACH,qBACa,QAAS,SAAQ,UAAU;IACZ,KAAK,SAAK;IACV,WAAW,SAAK;IAChB,WAAW,SAAK;IAChB,eAAe,EAAE,WAAW,CAAuB;IACnD,cAAc,EAAE,MAAM,GAAG,SAAS,CAAa;IAC9C,kBAAkB,UAAS;IAC3B,YAAY,EAAE,OAAO,CAAS;IACzD;;;;OAIG;IACwB,UAAU,EAAE,OAAO,CAAS;IACvD;;;OAGG;IACuB,IAAI,EAAE,YAAY,CAA4B;IACxE;;;OAGG;IACuB,QAAQ,EAAE,QAAQ,CAAoB;IAChE;;;;;;;;;;OAUG;IACuB,QAAQ,EAAE,MAAM,CAAM;IAEhD,OAAO,CAAC,SAAS,CAAgC;IAEjD,OAAO,KAAK,cAAc,GAIzB;IAED,OAAO,KAAK,cAAc,GAIzB;IAEQ,MAAM;IA4Hf,OAAO,CAAC,WAAW;IAuCnB,OAAO,KAAK,OAAO,GA4BlB;IAED,OAAgB,MAAM,0BA4BpB;CACH;AAED,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,WAAW,EAAE,QAAQ,CAAC;KACvB;CACF"}
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import { css, LitElement, nothing, svg, html } from "lit";
|
|
2
2
|
import { property } from "lit/decorators.js";
|
|
3
3
|
import { innerRingRadiusFor, WatchCircleType, OUTER_RING_RADIUS } from "../watch/watch.js";
|
|
4
|
+
import { ReadoutVariant, ReadoutDirection } from "../readout/readout.js";
|
|
5
|
+
import { Priority } from "../types.js";
|
|
4
6
|
import { TickmarkType } from "../watch/tickmark.js";
|
|
5
7
|
import { AdviceState, AdviceType } from "../watch/advice.js";
|
|
6
8
|
import { customElement } from "../../decorator.js";
|
|
7
9
|
import { normalizeArcAngle, computeZoomToFitArcFrame, shiftArcFrameToOuterEdge } from "../../svghelpers/arc-frame.js";
|
|
8
|
-
import { VesselImage,
|
|
10
|
+
import { VesselImage, vesselImages, VesselImageSize } from "../watch/vessel.js";
|
|
9
11
|
var __defProp = Object.defineProperty;
|
|
10
12
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
11
13
|
var __decorateClass = (decorators, target, key, kind) => {
|
|
@@ -18,6 +20,11 @@ var __decorateClass = (decorators, target, key, kind) => {
|
|
|
18
20
|
};
|
|
19
21
|
const watchRadius = OUTER_RING_RADIUS;
|
|
20
22
|
const CENTRE_HALF = 200;
|
|
23
|
+
var ObcPitchType = /* @__PURE__ */ ((ObcPitchType2) => {
|
|
24
|
+
ObcPitchType2["singleScale"] = "single-scale";
|
|
25
|
+
ObcPitchType2["dualScale"] = "dual-scale";
|
|
26
|
+
return ObcPitchType2;
|
|
27
|
+
})(ObcPitchType || {});
|
|
21
28
|
let ObcPitch = class extends LitElement {
|
|
22
29
|
constructor() {
|
|
23
30
|
super(...arguments);
|
|
@@ -28,8 +35,17 @@ let ObcPitch = class extends LitElement {
|
|
|
28
35
|
this.maxPitchAdvice = void 0;
|
|
29
36
|
this.triggerPitchAdvice = false;
|
|
30
37
|
this.zoomToFitArc = false;
|
|
38
|
+
this.hasReadout = false;
|
|
39
|
+
this.type = "single-scale";
|
|
40
|
+
this.priority = Priority.regular;
|
|
31
41
|
this.arcAngle = 45;
|
|
32
42
|
}
|
|
43
|
+
get scaleFillColor() {
|
|
44
|
+
return this.priority === Priority.enhanced ? "var(--instrument-enhanced-tertiary-color)" : "var(--instrument-regular-tertiary-color)";
|
|
45
|
+
}
|
|
46
|
+
get indicatorColor() {
|
|
47
|
+
return this.priority === Priority.enhanced ? "var(--instrument-enhanced-secondary-color)" : "var(--instrument-regular-secondary-color)";
|
|
48
|
+
}
|
|
33
49
|
render() {
|
|
34
50
|
const arcAngle = normalizeArcAngle(this.arcAngle, 45);
|
|
35
51
|
const x = watchRadius * Math.cos(arcAngle * Math.PI / 180);
|
|
@@ -67,96 +83,128 @@ let ObcPitch = class extends LitElement {
|
|
|
67
83
|
return html`
|
|
68
84
|
<div class="container">
|
|
69
85
|
<svg viewBox="${centreViewBox}">
|
|
70
|
-
${svg`
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
86
|
+
${this.hasReadout ? nothing : svg`
|
|
87
|
+
<line
|
|
88
|
+
x1="-${watchRadius}"
|
|
89
|
+
y1="0"
|
|
90
|
+
x2="${watchRadius}"
|
|
91
|
+
y2="0"
|
|
92
|
+
stroke="var(--instrument-frame-tertiary-color)"
|
|
93
|
+
/>
|
|
94
|
+
<line
|
|
95
|
+
x1="0"
|
|
96
|
+
y1="0"
|
|
97
|
+
x2="${watchRadius - 10}"
|
|
98
|
+
y2="0"
|
|
99
|
+
stroke="${this.indicatorColor}"
|
|
100
|
+
transform="${needleTransform}"
|
|
101
|
+
/>
|
|
102
|
+
<g
|
|
103
|
+
style="transform: rotate(${this.pitch}deg) scale(${vesselScale}) translate(-80px, -80px);"
|
|
104
|
+
>
|
|
105
|
+
${this.zoomToFitArc ? vesselImages[this.vesselImageSide] : nothing}
|
|
106
|
+
</g>
|
|
107
|
+
`}
|
|
108
|
+
${this.zoomToFitArc ? nothing : this.type === "dual-scale" ? svg`
|
|
109
|
+
<path
|
|
110
|
+
d="M ${x} ${-y} A ${watchRadius} ${watchRadius} 0 0 0 ${-x} ${-y}"
|
|
111
|
+
fill="none"
|
|
112
|
+
stroke="var(--instrument-frame-tertiary-color)"
|
|
113
|
+
/>
|
|
114
|
+
<path
|
|
115
|
+
d="M ${x} ${y} A ${watchRadius} ${watchRadius} 0 0 1 ${-x} ${y}"
|
|
116
|
+
fill="none"
|
|
117
|
+
stroke="var(--instrument-frame-tertiary-color)"
|
|
118
|
+
/>
|
|
119
|
+
` : svg`
|
|
120
|
+
<path
|
|
121
|
+
d="M ${x} ${y} A ${watchRadius} ${watchRadius} 0 1 1 ${x} ${-y}"
|
|
122
|
+
fill="none"
|
|
123
|
+
stroke="var(--instrument-frame-tertiary-color)"
|
|
124
|
+
/>
|
|
125
|
+
`}
|
|
99
126
|
</svg>
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
127
|
+
${this.renderScale(areas, false)}
|
|
128
|
+
${this.type === "dual-scale" ? this.renderScale(areas, true) : nothing}
|
|
129
|
+
${this.hasReadout ? html`<div class="readout">
|
|
130
|
+
<obc-readout
|
|
131
|
+
.variant=${ReadoutVariant.enhanced}
|
|
132
|
+
.direction=${ReadoutDirection.vertical}
|
|
133
|
+
.hasSetpoint=${false}
|
|
134
|
+
.hasAdvice=${false}
|
|
135
|
+
.value=${this.pitch}
|
|
136
|
+
.fractionDigits=${0}
|
|
137
|
+
.valuePriority=${this.priority}
|
|
138
|
+
label="Pitch"
|
|
139
|
+
unit="DEG"
|
|
140
|
+
></obc-readout>
|
|
141
|
+
</div>` : nothing}
|
|
142
|
+
</div>
|
|
143
|
+
`;
|
|
144
|
+
}
|
|
145
|
+
// `opposite` rotates a second watch 180° onto the opposite (left) arc for
|
|
146
|
+
// dual-scale — a rotation (opposite end of the indicator), not a mirror. A
|
|
147
|
+
// separate watch keeps the zoomed `arcFrame` correct.
|
|
148
|
+
renderScale(areas, opposite) {
|
|
149
|
+
return html`
|
|
150
|
+
<obc-watch
|
|
151
|
+
class=${opposite ? "scale-opposite" : nothing}
|
|
152
|
+
.priority=${this.priority}
|
|
153
|
+
.watchCircleType=${WatchCircleType.double}
|
|
154
|
+
.zoomToFitArc=${this.zoomToFitArc}
|
|
155
|
+
.arcFrame=${this._arcFrame}
|
|
156
|
+
tickmarksInside
|
|
157
|
+
.areas=${areas}
|
|
158
|
+
.barAreas=${[
|
|
106
159
|
{
|
|
107
160
|
startAngle: 90 + this.minAvgPitch,
|
|
108
161
|
endAngle: 90 + this.maxAvgPitch,
|
|
109
|
-
fillColor:
|
|
162
|
+
fillColor: this.scaleFillColor
|
|
110
163
|
}
|
|
111
164
|
]}
|
|
112
|
-
|
|
165
|
+
.needles=${[
|
|
113
166
|
{
|
|
114
167
|
angle: 90 + this.pitch,
|
|
115
|
-
fillColor:
|
|
168
|
+
fillColor: this.indicatorColor,
|
|
116
169
|
strokeColor: "var(--border-silhouette-color)"
|
|
117
170
|
}
|
|
118
171
|
]}
|
|
119
|
-
|
|
172
|
+
.vessels=${opposite || this.zoomToFitArc || this.hasReadout ? [] : [
|
|
120
173
|
{
|
|
121
174
|
size: VesselImageSize.large,
|
|
122
175
|
vesselImage: this.vesselImageSide,
|
|
123
176
|
transform: `rotate(${this.pitch}deg)`
|
|
124
177
|
}
|
|
125
178
|
]}
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
type: TickmarkType.main
|
|
130
|
-
}
|
|
131
|
-
]}
|
|
132
|
-
.advices=${this.advices}
|
|
133
|
-
></obc-watch>
|
|
134
|
-
</div>
|
|
179
|
+
.tickmarks=${[{ angle: 90, type: TickmarkType.main }]}
|
|
180
|
+
.advices=${this.advices}
|
|
181
|
+
></obc-watch>
|
|
135
182
|
`;
|
|
136
183
|
}
|
|
137
184
|
get advices() {
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
185
|
+
if (this.maxPitchAdvice === void 0) {
|
|
186
|
+
return [];
|
|
187
|
+
}
|
|
188
|
+
const arcAngle = normalizeArcAngle(this.arcAngle, 45);
|
|
189
|
+
const outer = Math.min(arcAngle, 30);
|
|
190
|
+
const inner = Math.min(this.maxPitchAdvice, outer);
|
|
191
|
+
const state = this.triggerPitchAdvice ? AdviceState.triggered : AdviceState.regular;
|
|
192
|
+
return [
|
|
193
|
+
{
|
|
145
194
|
minAngle: 90 - outer,
|
|
146
195
|
maxAngle: 90 - inner,
|
|
147
196
|
type: AdviceType.caution,
|
|
148
197
|
state,
|
|
149
198
|
hideMinTickmark: true
|
|
150
|
-
}
|
|
151
|
-
|
|
199
|
+
},
|
|
200
|
+
{
|
|
152
201
|
minAngle: 90 + inner,
|
|
153
202
|
maxAngle: 90 + outer,
|
|
154
203
|
type: AdviceType.caution,
|
|
155
204
|
state,
|
|
156
205
|
hideMaxTickmark: true
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
return advices;
|
|
206
|
+
}
|
|
207
|
+
];
|
|
160
208
|
}
|
|
161
209
|
};
|
|
162
210
|
ObcPitch.styles = css`
|
|
@@ -177,6 +225,16 @@ ObcPitch.styles = css`
|
|
|
177
225
|
width: 100%;
|
|
178
226
|
height: 100%;
|
|
179
227
|
}
|
|
228
|
+
|
|
229
|
+
.readout {
|
|
230
|
+
display: flex;
|
|
231
|
+
align-items: center;
|
|
232
|
+
justify-content: center;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
.scale-opposite {
|
|
236
|
+
transform: rotate(180deg);
|
|
237
|
+
}
|
|
180
238
|
`;
|
|
181
239
|
__decorateClass([
|
|
182
240
|
property({ type: Number })
|
|
@@ -199,6 +257,15 @@ __decorateClass([
|
|
|
199
257
|
__decorateClass([
|
|
200
258
|
property({ type: Boolean })
|
|
201
259
|
], ObcPitch.prototype, "zoomToFitArc", 2);
|
|
260
|
+
__decorateClass([
|
|
261
|
+
property({ type: Boolean })
|
|
262
|
+
], ObcPitch.prototype, "hasReadout", 2);
|
|
263
|
+
__decorateClass([
|
|
264
|
+
property({ type: String })
|
|
265
|
+
], ObcPitch.prototype, "type", 2);
|
|
266
|
+
__decorateClass([
|
|
267
|
+
property({ type: String })
|
|
268
|
+
], ObcPitch.prototype, "priority", 2);
|
|
202
269
|
__decorateClass([
|
|
203
270
|
property({ type: Number })
|
|
204
271
|
], ObcPitch.prototype, "arcAngle", 2);
|
|
@@ -206,6 +273,7 @@ ObcPitch = __decorateClass([
|
|
|
206
273
|
customElement("obc-pitch")
|
|
207
274
|
], ObcPitch);
|
|
208
275
|
export {
|
|
209
|
-
ObcPitch
|
|
276
|
+
ObcPitch,
|
|
277
|
+
ObcPitchType
|
|
210
278
|
};
|
|
211
279
|
//# sourceMappingURL=pitch.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pitch.js","sources":["../../../src/navigation-instruments/pitch/pitch.ts"],"sourcesContent":["import {LitElement, css, html, nothing, svg} from 'lit';\nimport {property} from 'lit/decorators.js';\nimport '../watch/watch.js';\nimport {\n VesselImage,\n VesselImageSize,\n WatchCircleType,\n OUTER_RING_RADIUS,\n innerRingRadiusFor,\n vesselImages,\n} from '../watch/watch.js';\nimport {TickmarkType} from '../watch/tickmark.js';\nimport {AdviceState, AdviceType, AngleAdviceRaw} from '../watch/advice.js';\nimport {customElement} from '../../decorator.js';\nimport {\n computeZoomToFitArcFrame,\n normalizeArcAngle,\n shiftArcFrameToOuterEdge,\n type ZoomToFitArcFrame,\n} from '../../svghelpers/arc-frame.js';\n\nconst watchRadius = OUTER_RING_RADIUS;\n/** Half-side of the centre overlay viewBox in SVG units. */\nconst CENTRE_HALF = 200;\n\n@customElement('obc-pitch')\nexport class ObcPitch extends LitElement {\n @property({type: Number}) pitch = 0;\n @property({type: Number}) minAvgPitch = 0;\n @property({type: Number}) maxAvgPitch = 0;\n @property({type: String}) vesselImageSide: VesselImage = VesselImage.psvSide;\n @property({type: Number}) maxPitchAdvice: number | undefined = undefined;\n @property({type: Boolean}) triggerPitchAdvice = false;\n @property({type: Boolean}) zoomToFitArc: boolean = false;\n /**\n * Half-extent of the watch arc in degrees. The arc spans `90° ± arcAngle`\n * and pitch values are placed at their true position within it. Default\n * `45` reproduces the historical 90°-wide arc.\n *\n * Smaller values render a narrower arc. Combined with `zoomToFitArc`, the\n * narrower arc is enlarged (its radius grows) on its own layer, while the\n * vessel image and the rotating indicator line stay at their natural size\n * and position on a separate central layer. The two layers are\n * intentionally visually disconnected.\n */\n @property({type: Number}) arcAngle: number = 45;\n\n private _arcFrame: ZoomToFitArcFrame | undefined;\n\n override render() {\n const arcAngle = normalizeArcAngle(this.arcAngle, 45);\n // Outer thin-ring complement endpoints. The arc band is centred at\n // watch angle 90° (right side) and spans 90° ± arcAngle, so its edges\n // sit at SVG coords (R·cos(arcAngle), ±R·sin(arcAngle)).\n const x = watchRadius * Math.cos((arcAngle * Math.PI) / 180);\n const y = watchRadius * Math.sin((arcAngle * Math.PI) / 180);\n\n const areas = [\n {\n startAngle: 90 - arcAngle,\n endAngle: 90 + arcAngle,\n roundOutsideCut: true,\n roundInsideCut: true,\n },\n ];\n\n if (this.zoomToFitArc) {\n const ext = 48;\n const targetSize = (176 + ext) * 2;\n // Pure arc-only fit (compass-sector style). The viewBox is centred on\n // the enlarged arc bbox, so the origin (centre of the instrument) is\n // typically OUTSIDE this viewBox. The vessel and central elements\n // therefore need their own normal-scale layer.\n const baseFrame = computeZoomToFitArcFrame({\n areas,\n outerRadius: OUTER_RING_RADIUS,\n innerRadius: innerRingRadiusFor(WatchCircleType.double),\n extension: ext,\n targetSize,\n });\n // Push the enlarged arc to the side so its outer edge aligns with the\n // central layer's outer ring. Direction is derived from the arc bbox\n // centre so left/right/top/bottom is handled automatically.\n this._arcFrame = shiftArcFrameToOuterEdge(\n baseFrame,\n OUTER_RING_RADIUS + baseFrame.radiusOffset,\n OUTER_RING_RADIUS,\n CENTRE_HALF\n );\n } else {\n this._arcFrame = undefined;\n }\n\n const needleTransform = `rotate(${this.pitch} 0 0)`;\n const centreViewBox = `-${CENTRE_HALF} -${CENTRE_HALF} ${CENTRE_HALF * 2} ${CENTRE_HALF * 2}`;\n const vesselScale = 224 / 160;\n\n return html`\n <div class=\"container\">\n <svg viewBox=\"${centreViewBox}\">\n ${svg`\n <line\n x1=\"-${watchRadius}\"\n y1=\"0\"\n x2=\"${watchRadius}\"\n y2=\"0\"\n stroke=\"var(--instrument-frame-tertiary-color)\"\n />\n <line\n x1=\"0\"\n y1=\"0\"\n x2=\"${watchRadius - 10}\"\n y2=\"0\"\n stroke=\"var(--instrument-enhanced-secondary-color)\"\n transform=\"${needleTransform}\"\n />\n <g\n style=\"transform: rotate(${this.pitch}deg) scale(${vesselScale}) translate(-80px, -80px);\"\n >\n ${vesselImages[this.vesselImageSide]}\n </g>\n ${\n this.zoomToFitArc\n ? nothing\n : svg`\n <path\n d=\"M ${x} ${y} A ${watchRadius} ${watchRadius} 0 1 1 ${x} ${-y}\"\n fill=\"none\"\n stroke=\"var(--instrument-frame-tertiary-color)\"\n />\n `\n }\n `}\n </svg>\n <obc-watch\n .watchCircleType=${WatchCircleType.double}\n .zoomToFitArc=${this.zoomToFitArc}\n .arcFrame=${this._arcFrame}\n .areas=${areas}\n .barAreas=${[\n {\n startAngle: 90 + this.minAvgPitch,\n endAngle: 90 + this.maxAvgPitch,\n fillColor: 'var(--instrument-enhanced-tertiary-color)',\n },\n ]}\n .needles=${[\n {\n angle: 90 + this.pitch,\n fillColor: 'var(--instrument-enhanced-secondary-color)',\n strokeColor: 'var(--border-silhouette-color)',\n },\n ]}\n .vessels=${this.zoomToFitArc\n ? []\n : [\n {\n size: VesselImageSize.large,\n vesselImage: this.vesselImageSide,\n transform: `rotate(${this.pitch}deg)`,\n },\n ]}\n .tickmarks=${[\n {\n angle: 90,\n type: TickmarkType.main,\n },\n ]}\n .advices=${this.advices}\n ></obc-watch>\n </div>\n `;\n }\n\n private get advices(): AngleAdviceRaw[] {\n const advices = [];\n if (this.maxPitchAdvice !== undefined) {\n const arcAngle = normalizeArcAngle(this.arcAngle, 45);\n // Caution band fills the remainder of the arc out to a default 30°\n // caution range (clamped to the arc edge).\n const outer = Math.min(arcAngle, 30);\n const inner = Math.min(this.maxPitchAdvice, outer);\n const state = this.triggerPitchAdvice\n ? AdviceState.triggered\n : AdviceState.regular;\n advices.push({\n minAngle: 90 - outer,\n maxAngle: 90 - inner,\n type: AdviceType.caution,\n state: state,\n hideMinTickmark: true,\n });\n advices.push({\n minAngle: 90 + inner,\n maxAngle: 90 + outer,\n type: AdviceType.caution,\n state: state,\n hideMaxTickmark: true,\n });\n }\n return advices;\n }\n\n static override styles = css`\n * {\n box-sizing: border-box;\n }\n\n .container {\n position: relative;\n width: 100%;\n height: 100%;\n }\n\n .container > * {\n position: absolute;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n }\n `;\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'obc-pitch': ObcPitch;\n }\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"pitch.js","sources":["../../../src/navigation-instruments/pitch/pitch.ts"],"sourcesContent":["import {LitElement, css, html, nothing, svg} from 'lit';\nimport {property} from 'lit/decorators.js';\nimport '../watch/watch.js';\nimport {\n VesselImage,\n VesselImageSize,\n WatchCircleType,\n OUTER_RING_RADIUS,\n innerRingRadiusFor,\n vesselImages,\n type WatchArea,\n} from '../watch/watch.js';\nimport '../readout/readout.js';\nimport {ReadoutDirection, ReadoutVariant} from '../readout/readout.js';\nimport {Priority} from '../types.js';\nimport {TickmarkType} from '../watch/tickmark.js';\nimport {AdviceState, AdviceType, AngleAdviceRaw} from '../watch/advice.js';\nimport {customElement} from '../../decorator.js';\nimport {\n computeZoomToFitArcFrame,\n normalizeArcAngle,\n shiftArcFrameToOuterEdge,\n type ZoomToFitArcFrame,\n} from '../../svghelpers/arc-frame.js';\n\nconst watchRadius = OUTER_RING_RADIUS;\n/** Half-side of the centre overlay viewBox in SVG units. */\nconst CENTRE_HALF = 200;\n\nexport enum ObcPitchType {\n /** Single arc scale on the right (default). */\n singleScale = 'single-scale',\n /** Right scale duplicated to the opposite (left) arc as well. */\n dualScale = 'dual-scale',\n}\n\n/**\n * `<obc-pitch>` — Pitch (trim) indicator with a side arc scale.\n *\n * Shows `pitch` against a watch arc centred on the right, with an average-pitch\n * band and a rotating indicator. Supports an optional opposite-side scale\n * (`dual-scale`), a centre readout (`hasReadout`), and a `regular`/`enhanced`\n * palette.\n *\n * @element obc-pitch\n */\n@customElement('obc-pitch')\nexport class ObcPitch extends LitElement {\n @property({type: Number}) pitch = 0;\n @property({type: Number}) minAvgPitch = 0;\n @property({type: Number}) maxAvgPitch = 0;\n @property({type: String}) vesselImageSide: VesselImage = VesselImage.psvSide;\n @property({type: Number}) maxPitchAdvice: number | undefined = undefined;\n @property({type: Boolean}) triggerPitchAdvice = false;\n @property({type: Boolean}) zoomToFitArc: boolean = false;\n /**\n * When `true`, the centre shows an `<obc-readout>` with the pitch value\n * (label `Pitch`, unit `DEG`) instead of the horizon line, rotating indicator\n * and vessel. Default `false`.\n */\n @property({type: Boolean}) hasReadout: boolean = false;\n /**\n * `single-scale` shows one arc on the right (default); `dual-scale` also\n * shows the scale on the opposite (left) arc (the indicator's opposite end).\n */\n @property({type: String}) type: ObcPitchType = ObcPitchType.singleScale;\n /**\n * Colour palette for the scale fill / indicator and the readout value:\n * `regular` (default) or `enhanced`.\n */\n @property({type: String}) priority: Priority = Priority.regular;\n /**\n * Half-extent of the watch arc in degrees. The arc spans `90° ± arcAngle`\n * and pitch values are placed at their true position within it. Default\n * `45` reproduces the historical 90°-wide arc.\n *\n * Smaller values render a narrower arc. Combined with `zoomToFitArc`, the\n * narrower arc is enlarged (its radius grows) on its own layer, while the\n * vessel image and the rotating indicator line stay at their natural size\n * and position on a separate central layer. The two layers are\n * intentionally visually disconnected.\n */\n @property({type: Number}) arcAngle: number = 45;\n\n private _arcFrame: ZoomToFitArcFrame | undefined;\n\n private get scaleFillColor(): string {\n return this.priority === Priority.enhanced\n ? 'var(--instrument-enhanced-tertiary-color)'\n : 'var(--instrument-regular-tertiary-color)';\n }\n\n private get indicatorColor(): string {\n return this.priority === Priority.enhanced\n ? 'var(--instrument-enhanced-secondary-color)'\n : 'var(--instrument-regular-secondary-color)';\n }\n\n override render() {\n const arcAngle = normalizeArcAngle(this.arcAngle, 45);\n // Outer thin-ring complement endpoints. The arc band is centred at\n // watch angle 90° (right side) and spans 90° ± arcAngle, so its edges\n // sit at SVG coords (R·cos(arcAngle), ±R·sin(arcAngle)).\n const x = watchRadius * Math.cos((arcAngle * Math.PI) / 180);\n const y = watchRadius * Math.sin((arcAngle * Math.PI) / 180);\n\n const areas: WatchArea[] = [\n {\n startAngle: 90 - arcAngle,\n endAngle: 90 + arcAngle,\n roundOutsideCut: true,\n roundInsideCut: true,\n },\n ];\n\n if (this.zoomToFitArc) {\n const ext = 48;\n const targetSize = (176 + ext) * 2;\n // Pure arc-only fit (compass-sector style). The viewBox is centred on\n // the enlarged arc bbox, so the origin (centre of the instrument) is\n // typically OUTSIDE this viewBox. The vessel and central elements\n // therefore need their own normal-scale layer.\n const baseFrame = computeZoomToFitArcFrame({\n areas,\n outerRadius: OUTER_RING_RADIUS,\n innerRadius: innerRingRadiusFor(WatchCircleType.double),\n extension: ext,\n targetSize,\n });\n // Push the enlarged arc to the side so its outer edge aligns with the\n // central layer's outer ring. Direction is derived from the arc bbox\n // centre so left/right/top/bottom is handled automatically.\n this._arcFrame = shiftArcFrameToOuterEdge(\n baseFrame,\n OUTER_RING_RADIUS + baseFrame.radiusOffset,\n OUTER_RING_RADIUS,\n CENTRE_HALF\n );\n } else {\n this._arcFrame = undefined;\n }\n\n const needleTransform = `rotate(${this.pitch} 0 0)`;\n const centreViewBox = `-${CENTRE_HALF} -${CENTRE_HALF} ${CENTRE_HALF * 2} ${CENTRE_HALF * 2}`;\n const vesselScale = 224 / 160;\n\n return html`\n <div class=\"container\">\n <svg viewBox=\"${centreViewBox}\">\n ${this.hasReadout\n ? nothing\n : svg`\n <line\n x1=\"-${watchRadius}\"\n y1=\"0\"\n x2=\"${watchRadius}\"\n y2=\"0\"\n stroke=\"var(--instrument-frame-tertiary-color)\"\n />\n <line\n x1=\"0\"\n y1=\"0\"\n x2=\"${watchRadius - 10}\"\n y2=\"0\"\n stroke=\"${this.indicatorColor}\"\n transform=\"${needleTransform}\"\n />\n <g\n style=\"transform: rotate(${this.pitch}deg) scale(${vesselScale}) translate(-80px, -80px);\"\n >\n ${this.zoomToFitArc ? vesselImages[this.vesselImageSide] : nothing}\n </g>\n `}\n ${this.zoomToFitArc\n ? nothing\n : this.type === ObcPitchType.dualScale\n ? svg`\n <path\n d=\"M ${x} ${-y} A ${watchRadius} ${watchRadius} 0 0 0 ${-x} ${-y}\"\n fill=\"none\"\n stroke=\"var(--instrument-frame-tertiary-color)\"\n />\n <path\n d=\"M ${x} ${y} A ${watchRadius} ${watchRadius} 0 0 1 ${-x} ${y}\"\n fill=\"none\"\n stroke=\"var(--instrument-frame-tertiary-color)\"\n />\n `\n : svg`\n <path\n d=\"M ${x} ${y} A ${watchRadius} ${watchRadius} 0 1 1 ${x} ${-y}\"\n fill=\"none\"\n stroke=\"var(--instrument-frame-tertiary-color)\"\n />\n `}\n </svg>\n ${this.renderScale(areas, false)}\n ${this.type === ObcPitchType.dualScale\n ? this.renderScale(areas, true)\n : nothing}\n ${this.hasReadout\n ? html`<div class=\"readout\">\n <obc-readout\n .variant=${ReadoutVariant.enhanced}\n .direction=${ReadoutDirection.vertical}\n .hasSetpoint=${false}\n .hasAdvice=${false}\n .value=${this.pitch}\n .fractionDigits=${0}\n .valuePriority=${this.priority}\n label=\"Pitch\"\n unit=\"DEG\"\n ></obc-readout>\n </div>`\n : nothing}\n </div>\n `;\n }\n\n // `opposite` rotates a second watch 180° onto the opposite (left) arc for\n // dual-scale — a rotation (opposite end of the indicator), not a mirror. A\n // separate watch keeps the zoomed `arcFrame` correct.\n private renderScale(areas: WatchArea[], opposite: boolean) {\n return html`\n <obc-watch\n class=${opposite ? 'scale-opposite' : nothing}\n .priority=${this.priority}\n .watchCircleType=${WatchCircleType.double}\n .zoomToFitArc=${this.zoomToFitArc}\n .arcFrame=${this._arcFrame}\n tickmarksInside\n .areas=${areas}\n .barAreas=${[\n {\n startAngle: 90 + this.minAvgPitch,\n endAngle: 90 + this.maxAvgPitch,\n fillColor: this.scaleFillColor,\n },\n ]}\n .needles=${[\n {\n angle: 90 + this.pitch,\n fillColor: this.indicatorColor,\n strokeColor: 'var(--border-silhouette-color)',\n },\n ]}\n .vessels=${opposite || this.zoomToFitArc || this.hasReadout\n ? []\n : [\n {\n size: VesselImageSize.large,\n vesselImage: this.vesselImageSide,\n transform: `rotate(${this.pitch}deg)`,\n },\n ]}\n .tickmarks=${[{angle: 90, type: TickmarkType.main}]}\n .advices=${this.advices}\n ></obc-watch>\n `;\n }\n\n private get advices(): AngleAdviceRaw[] {\n if (this.maxPitchAdvice === undefined) {\n return [];\n }\n const arcAngle = normalizeArcAngle(this.arcAngle, 45);\n // Caution band fills the remainder of the arc out to a default 30° caution\n // range (clamped to the arc edge).\n const outer = Math.min(arcAngle, 30);\n const inner = Math.min(this.maxPitchAdvice, outer);\n const state = this.triggerPitchAdvice\n ? AdviceState.triggered\n : AdviceState.regular;\n return [\n {\n minAngle: 90 - outer,\n maxAngle: 90 - inner,\n type: AdviceType.caution,\n state: state,\n hideMinTickmark: true,\n },\n {\n minAngle: 90 + inner,\n maxAngle: 90 + outer,\n type: AdviceType.caution,\n state: state,\n hideMaxTickmark: true,\n },\n ];\n }\n\n static override styles = css`\n * {\n box-sizing: border-box;\n }\n\n .container {\n position: relative;\n width: 100%;\n height: 100%;\n }\n\n .container > * {\n position: absolute;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n }\n\n .readout {\n display: flex;\n align-items: center;\n justify-content: center;\n }\n\n .scale-opposite {\n transform: rotate(180deg);\n }\n `;\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'obc-pitch': ObcPitch;\n }\n}\n"],"names":["ObcPitchType"],"mappings":"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"}
|
|
@@ -2,6 +2,7 @@ import { LitElement } from 'lit';
|
|
|
2
2
|
import { VesselImage } from '../watch/watch.js';
|
|
3
3
|
import { Priority } from '../types.js';
|
|
4
4
|
import '../watch/watch.js';
|
|
5
|
+
import '../readout/readout.js';
|
|
5
6
|
export declare enum PitchRollPriorityElement {
|
|
6
7
|
pitch = "pitch",
|
|
7
8
|
roll = "roll"
|
|
@@ -22,6 +23,11 @@ export declare class ObcPitchRoll extends LitElement {
|
|
|
22
23
|
triggerRollAdvice: boolean;
|
|
23
24
|
priority: Priority;
|
|
24
25
|
priorityElements: PitchRollPriorityElement[];
|
|
26
|
+
/**
|
|
27
|
+
* When `true`, the centre shows two stacked `<obc-readout>`s (pitch above
|
|
28
|
+
* roll) instead of the vessel images. Default `false`.
|
|
29
|
+
*/
|
|
30
|
+
hasReadout: boolean;
|
|
25
31
|
zoomToFitArc: boolean;
|
|
26
32
|
/**
|
|
27
33
|
* Half-extent of each of the four watch arcs in degrees, measured from the
|
|
@@ -50,6 +56,7 @@ export declare class ObcPitchRoll extends LitElement {
|
|
|
50
56
|
private get requestedPitchArcAngle();
|
|
51
57
|
private get requestedRollArcAngle();
|
|
52
58
|
render(): import('lit-html').TemplateResult<1>;
|
|
59
|
+
private renderReadout;
|
|
53
60
|
/**
|
|
54
61
|
* Zoomed-arc layer: four CSS-rotated `<obc-watch>` instances, each
|
|
55
62
|
* containing a single arc rendered at the watch's natural top
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pitch-roll.d.ts","sourceRoot":"","sources":["../../../src/navigation-instruments/pitch-roll/pitch-roll.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,UAAU,EAA0B,MAAM,KAAK,CAAC;AAExD,OAAO,mBAAmB,CAAC;AAC3B,OAAO,EACL,WAAW,EAOZ,MAAM,mBAAmB,CAAC;AAI3B,OAAO,EAAC,QAAQ,EAAC,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"pitch-roll.d.ts","sourceRoot":"","sources":["../../../src/navigation-instruments/pitch-roll/pitch-roll.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,UAAU,EAA0B,MAAM,KAAK,CAAC;AAExD,OAAO,mBAAmB,CAAC;AAC3B,OAAO,EACL,WAAW,EAOZ,MAAM,mBAAmB,CAAC;AAI3B,OAAO,EAAC,QAAQ,EAAC,MAAM,aAAa,CAAC;AACrC,OAAO,uBAAuB,CAAC;AAQ/B,oBAAY,wBAAwB;IAClC,KAAK,UAAU;IACf,IAAI,SAAS;CACd;AAqBD,qBACa,YAAa,SAAQ,UAAU;IAChB,KAAK,SAAK;IACV,IAAI,SAAK;IACT,WAAW,SAAK;IAChB,WAAW,SAAK;IAChB,UAAU,SAAK;IACf,UAAU,SAAK;IACf,eAAe,EAAE,WAAW,CAAuB;IACnD,eAAe,EAAE,WAAW,CAAuB;IACnD,cAAc,SAAK;IACnB,cAAc,EAAE,MAAM,GAAG,SAAS,CAAa;IAC/C,aAAa,EAAE,MAAM,GAAG,SAAS,CAAa;IAC7C,kBAAkB,UAAS;IAC3B,iBAAiB,UAAS;IAC3B,QAAQ,EAAE,QAAQ,CAAoB;IAEhE,gBAAgB,EAAE,wBAAwB,EAAE,CAG1C;IACF;;;OAGG;IACwB,UAAU,EAAE,OAAO,CAAS;IAC5B,YAAY,EAAE,OAAO,CAAS;IACzD;;;;;;OAMG;IACuB,QAAQ,EAAE,MAAM,CAAM;IAChD;;;;OAIG;IACuB,aAAa,CAAC,EAAE,MAAM,CAAC;IACjD;;;OAGG;IACuB,YAAY,CAAC,EAAE,MAAM,CAAC;IAEhD,OAAO,CAAC,WAAW;IAOnB,OAAO,CAAC,WAAW;IAMnB,OAAO,CAAC,QAAQ;IAMhB,OAAO,KAAK,wBAAwB,GAKnC;IAED,kEAAkE;IAClE,OAAO,KAAK,sBAAsB,GAEjC;IACD,OAAO,KAAK,qBAAqB,GAEhC;IAEQ,MAAM;IAkFf,OAAO,CAAC,aAAa;IAoBrB;;;;;;;;;;;;;;;;;;;;;;OAsBG;IACH,OAAO,CAAC,gBAAgB;IA6RxB;;;;;;OAMG;IACH,OAAO,CAAC,UAAU;IA8BlB,6DAA6D;IAC7D,OAAO,CAAC,eAAe;IA2EvB,OAAO,KAAK,OAAO,GA2ElB;IAED,OAAgB,MAAM,0BAqCpB;CACH;AAED,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,gBAAgB,EAAE,YAAY,CAAC;KAChC;CACF"}
|