@oicl/openbridge-webcomponents 2.0.0-next.56 → 2.0.0-next.58
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 +987 -362
- package/bundle/openbridge-webcomponents.bundle.js.map +1 -1
- package/custom-elements.json +576 -10
- package/dist/building-blocks/instrument-radial/instrument-radial.d.ts +10 -0
- package/dist/building-blocks/instrument-radial/instrument-radial.d.ts.map +1 -1
- package/dist/building-blocks/instrument-radial/instrument-radial.js +86 -21
- package/dist/building-blocks/instrument-radial/instrument-radial.js.map +1 -1
- 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/gauge-radial/gauge-radial.css.js +99 -0
- package/dist/navigation-instruments/gauge-radial/gauge-radial.css.js.map +1 -0
- package/dist/navigation-instruments/gauge-radial/gauge-radial.d.ts +42 -7
- package/dist/navigation-instruments/gauge-radial/gauge-radial.d.ts.map +1 -1
- package/dist/navigation-instruments/gauge-radial/gauge-radial.js +178 -31
- package/dist/navigation-instruments/gauge-radial/gauge-radial.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/readout/readout.css.js +4 -0
- package/dist/navigation-instruments/readout/readout.css.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/dist/navigation-instruments/watch/tickmark.d.ts +2 -1
- package/dist/navigation-instruments/watch/tickmark.d.ts.map +1 -1
- package/dist/navigation-instruments/watch/tickmark.js +24 -4
- package/dist/navigation-instruments/watch/tickmark.js.map +1 -1
- package/dist/navigation-instruments/watch/watch.d.ts +23 -1
- package/dist/navigation-instruments/watch/watch.d.ts.map +1 -1
- package/dist/navigation-instruments/watch/watch.js +48 -20
- package/dist/navigation-instruments/watch/watch.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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"}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { css } from "lit";
|
|
2
|
+
const componentStyle = css`
|
|
3
|
+
* {
|
|
4
|
+
-webkit-tap-highlight-color: transparent;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
:host {
|
|
8
|
+
display: block;
|
|
9
|
+
width: 100%;
|
|
10
|
+
height: 100%;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/* Host takes each sector's crop aspect (see \`sectorClips\`): 270/90 square, 180
|
|
14
|
+
wide — so the dial is the same size at any width. */
|
|
15
|
+
|
|
16
|
+
:host([sector="270"]),
|
|
17
|
+
:host([sector="90-left"]),
|
|
18
|
+
:host([sector="90-right"]) {
|
|
19
|
+
height: auto;
|
|
20
|
+
aspect-ratio: 1;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/* 448 / 251 = the 180° crop's aspect (448 wide × 448·(1 − 44%) tall); keep in
|
|
24
|
+
sync with \`sectorClips\` bottom=44 in gauge-radial.ts. */
|
|
25
|
+
|
|
26
|
+
:host([sector="180"]) {
|
|
27
|
+
height: auto;
|
|
28
|
+
aspect-ratio: 448 / 251;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
.gauge-radial-root {
|
|
32
|
+
/* Readout vertical placement per layout (% of the cropped host), tuned to the
|
|
33
|
+
watch geometry — re-check if the ring radii or the 448 box change. Which
|
|
34
|
+
layout uses which is in renderReadouts(). */
|
|
35
|
+
--readout-meta-top: 72%;
|
|
36
|
+
--readout-meta-top-needle: 63%;
|
|
37
|
+
--readout-meta-top-180: 60%;
|
|
38
|
+
|
|
39
|
+
position: relative;
|
|
40
|
+
width: 100%;
|
|
41
|
+
height: 100%;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
.gauge-radial-root .gauge-readout-value {
|
|
45
|
+
position: absolute;
|
|
46
|
+
left: 50%;
|
|
47
|
+
top: 50%;
|
|
48
|
+
transform: translate(-50%, -50%);
|
|
49
|
+
z-index: 1;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
.gauge-radial-root .gauge-readout-meta {
|
|
53
|
+
position: absolute;
|
|
54
|
+
left: 50%;
|
|
55
|
+
top: var(--readout-meta-top);
|
|
56
|
+
transform: translateX(-50%);
|
|
57
|
+
z-index: 1;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
.gauge-radial-root.type-needle .gauge-readout-meta {
|
|
61
|
+
top: var(--readout-meta-top-needle);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
.gauge-radial-root.sector-180 .gauge-readout-meta {
|
|
65
|
+
top: var(--readout-meta-top-180);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/* Nudge the corner readout inward (up + toward center) so it sits inside the
|
|
69
|
+
open quadrant rather than hugging the box corner. Symmetric for both
|
|
70
|
+
orientations — only the horizontal edge differs. */
|
|
71
|
+
|
|
72
|
+
.gauge-radial-root.sector-90-left .gauge-readout-meta,.gauge-radial-root.sector-90-right .gauge-readout-meta {
|
|
73
|
+
--readout-90-inset: 6%;
|
|
74
|
+
bottom: var(--readout-90-inset);
|
|
75
|
+
top: auto;
|
|
76
|
+
transform: none;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
.gauge-radial-root.sector-90-left .gauge-readout-meta {
|
|
80
|
+
left: auto;
|
|
81
|
+
right: var(--readout-90-inset);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
.gauge-radial-root.sector-90-right .gauge-readout-meta {
|
|
85
|
+
left: var(--readout-90-inset);
|
|
86
|
+
right: auto;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/* 90-right readout sits in the bottom-left corner, so left-align the value
|
|
90
|
+
under the label (enhanced readouts right-align the value by default). */
|
|
91
|
+
|
|
92
|
+
.gauge-radial-root.sector-90-right .gauge-readout-meta::part(value-wrapper) {
|
|
93
|
+
justify-self: start;
|
|
94
|
+
}
|
|
95
|
+
`;
|
|
96
|
+
export {
|
|
97
|
+
componentStyle as default
|
|
98
|
+
};
|
|
99
|
+
//# sourceMappingURL=gauge-radial.css.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gauge-radial.css.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
|
|
@@ -1,13 +1,20 @@
|
|
|
1
|
-
import { LitElement } from 'lit';
|
|
1
|
+
import { LitElement, TemplateResult } from 'lit';
|
|
2
2
|
import { AdviceType } from '../watch/advice.js';
|
|
3
3
|
import { InstrumentState, Priority } from '../types.js';
|
|
4
4
|
import { TickmarkStyle } from '../watch/tickmark.js';
|
|
5
5
|
import '../../building-blocks/instrument-radial/instrument-radial.js';
|
|
6
|
+
import '../readout/readout.js';
|
|
6
7
|
export declare enum ObcGaugeRadialType {
|
|
7
8
|
filled = "filled",
|
|
8
9
|
bar = "bar",
|
|
9
10
|
needle = "needle"
|
|
10
11
|
}
|
|
12
|
+
export declare enum GaugeRadialSector {
|
|
13
|
+
deg270 = "270",
|
|
14
|
+
deg180 = "180",
|
|
15
|
+
deg90Left = "90-left",
|
|
16
|
+
deg90Right = "90-right"
|
|
17
|
+
}
|
|
11
18
|
export interface GaugeRadialAdvice {
|
|
12
19
|
minValue: number;
|
|
13
20
|
maxValue: number;
|
|
@@ -29,14 +36,17 @@ declare const ObcGaugeRadial_base: (new (...args: any[]) => import('../../svghel
|
|
|
29
36
|
*
|
|
30
37
|
* - **Three display types**: `filled` (solid arc), `bar` (thinner arc), and
|
|
31
38
|
* `needle` (pointer indicator) via the `type` property.
|
|
32
|
-
* - **
|
|
33
|
-
*
|
|
39
|
+
* - **Sector sweep**: `sector` selects the arc span (`270`, `180`, `90-left`, or `90-right`).
|
|
40
|
+
* The configured `minValue..maxValue` always spans the full sector. For the
|
|
41
|
+
* centered sectors (`270`, `180`) a symmetric range places `0` at 12 o'clock;
|
|
42
|
+
* for `90-left`/`90-right` the range midpoint sits at the middle of the quadrant.
|
|
34
43
|
* - **Setpoint via mixin**: `setpoint`, `newSetpoint`, `touching`,
|
|
35
44
|
* `autoAtSetpointDeadband`, `setpointOverride`, and all other setpoint
|
|
36
45
|
* properties are provided by `SetpointMixin` and forwarded to the inner
|
|
37
46
|
* `<obc-instrument-radial>`.
|
|
38
47
|
* - **Advice zones**: Pass an array of {@link GaugeRadialAdvice} objects to
|
|
39
|
-
* render caution/alert arcs on the gauge.
|
|
48
|
+
* render caution/alert arcs on the gauge. Not shown on the `90-left` /
|
|
49
|
+
* `90-right` sectors.
|
|
40
50
|
*
|
|
41
51
|
* ## Usage Guidelines
|
|
42
52
|
*
|
|
@@ -45,6 +55,12 @@ declare const ObcGaugeRadial_base: (new (...args: any[]) => import('../../svghel
|
|
|
45
55
|
* - Provide `primaryTickmarkInterval` and `secondaryTickmarkInterval` to
|
|
46
56
|
* control tickmark density.
|
|
47
57
|
* - Enable `showLabels` to show numeric labels at primary tickmarks.
|
|
58
|
+
* - Enable `showReadout` with optional `label` and `unit`. Layout depends on `sector`
|
|
59
|
+
* and `type`: **270** filled/bar — value at center + a label-only `meta` row in
|
|
60
|
+
* the bottom gap (two separate readouts); **180** filled/bar — a single centered
|
|
61
|
+
* stack (value + label/unit) at the bottom; **270** needle — bottom stack;
|
|
62
|
+
* **180** needle — no readout; **90-left** / **90-right** filled/bar — corner
|
|
63
|
+
* readout in a square host; **90** needle — no readout.
|
|
48
64
|
*
|
|
49
65
|
* ## Best Practices
|
|
50
66
|
*
|
|
@@ -61,7 +77,7 @@ declare const ObcGaugeRadial_base: (new (...args: any[]) => import('../../svghel
|
|
|
61
77
|
* minValue="0"
|
|
62
78
|
* maxValue="100"
|
|
63
79
|
* type="filled"
|
|
64
|
-
* enhanced
|
|
80
|
+
* priority="enhanced"
|
|
65
81
|
* showLabels
|
|
66
82
|
* primaryTickmarkInterval="25"
|
|
67
83
|
* secondaryTickmarkInterval="5"
|
|
@@ -89,9 +105,28 @@ export declare class ObcGaugeRadial extends ObcGaugeRadial_base {
|
|
|
89
105
|
type: ObcGaugeRadialType;
|
|
90
106
|
tickmarksInside: boolean;
|
|
91
107
|
tickmarkStyle: TickmarkStyle;
|
|
108
|
+
/** Caution/alert arcs. Ignored on `sector: 90-left` / `90-right`. */
|
|
92
109
|
advices: GaugeRadialAdvice[];
|
|
93
|
-
|
|
94
|
-
|
|
110
|
+
sector: GaugeRadialSector;
|
|
111
|
+
showReadout: boolean;
|
|
112
|
+
label: string;
|
|
113
|
+
unit: string;
|
|
114
|
+
fractionDigits: number;
|
|
115
|
+
private get sectorAngles();
|
|
116
|
+
/**
|
|
117
|
+
* Per-edge crop (%) of the shared, origin-centered 448 SVG box each sector
|
|
118
|
+
* shows. All sectors render at the same natural scale, so the dial stays the
|
|
119
|
+
* same size; the sector only windows a different part (270 whole, 180 wide,
|
|
120
|
+
* 90 a quadrant).
|
|
121
|
+
*/
|
|
122
|
+
private get sectorClips();
|
|
123
|
+
private get isSector90();
|
|
124
|
+
getAngle: (v: number) => number;
|
|
125
|
+
/** Renders one gauge readout; `withMeta`/`labelOnly` pick parts. */
|
|
126
|
+
private renderReadout;
|
|
127
|
+
private renderReadouts;
|
|
128
|
+
render(): TemplateResult<1>;
|
|
129
|
+
static styles: import('lit').CSSResult;
|
|
95
130
|
}
|
|
96
131
|
declare global {
|
|
97
132
|
interface HTMLElementTagNameMap {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gauge-radial.d.ts","sourceRoot":"","sources":["../../../src/navigation-instruments/gauge-radial/gauge-radial.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,UAAU,
|
|
1
|
+
{"version":3,"file":"gauge-radial.d.ts","sourceRoot":"","sources":["../../../src/navigation-instruments/gauge-radial/gauge-radial.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,UAAU,EAA4B,KAAK,cAAc,EAAC,MAAM,KAAK,CAAC;AAK9E,OAAO,EAAC,UAAU,EAAC,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAC,eAAe,EAAE,QAAQ,EAAC,MAAM,aAAa,CAAC;AAEtD,OAAO,8DAA8D,CAAC;AACtE,OAAO,EAAC,aAAa,EAAC,MAAM,sBAAsB,CAAC;AACnD,OAAO,uBAAuB,CAAC;AAM/B,oBAAY,kBAAkB;IAC5B,MAAM,WAAW;IACjB,GAAG,QAAQ;IACX,MAAM,WAAW;CAClB;AAED,oBAAY,iBAAiB;IAC3B,MAAM,QAAQ;IACd,MAAM,QAAQ;IACd,SAAS,YAAY;IACrB,UAAU,aAAa;CACxB;AAED,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,UAAU,CAAC;IACjB,MAAM,EAAE,OAAO,CAAC;CACjB;;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiEG;AACH,qBACa,cAAe,SAAQ,mBAAyB;IACjC,KAAK,SAAK;IACV,QAAQ,SAAO;IACf,QAAQ,SAAK;IACZ,UAAU,EAAE,OAAO,CAAS;IAC7B,uBAAuB,SAAM;IAC7B,yBAAyB,SAAM;IACzD;;;OAGG;IACuB,wBAAwB,EAAE,MAAM,GAAG,SAAS,CAC1D;IACc,KAAK,EAAE,eAAe,CAA0B;IAChD,QAAQ,EAAE,QAAQ,CAAoB;IACtC,IAAI,EAAE,kBAAkB,CACtB;IACD,eAAe,EAAE,OAAO,CAAS;IAClC,aAAa,EAAE,aAAa,CAC9B;IACxB,qEAAqE;IAC1B,OAAO,EAAE,iBAAiB,EAAE,CAAM;IACpC,MAAM,EAAE,iBAAiB,CACvC;IACA,WAAW,UAAS;IACrB,KAAK,SAAM;IACX,IAAI,SAAM;IACV,cAAc,SAAK;IAE7C,OAAO,KAAK,YAAY,GAYvB;IAED;;;;;OAKG;IACH,OAAO,KAAK,WAAW,GAiBtB;IAED,OAAO,KAAK,UAAU,GAKrB;IAID,QAAQ,GAAI,GAAG,MAAM,KAAG,MAAM,CAQ5B;IAEF,oEAAoE;IACpE,OAAO,CAAC,aAAa;IA+BrB,OAAO,CAAC,cAAc;IAiDb,MAAM;IAgDf,OAAgB,MAAM,0BAA6B;CACpD;AAED,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,kBAAkB,EAAE,cAAc,CAAC;KACpC;CACF"}
|
|
@@ -1,10 +1,13 @@
|
|
|
1
|
-
import { LitElement, html } from "lit";
|
|
1
|
+
import { LitElement, html, nothing, unsafeCSS } from "lit";
|
|
2
|
+
import { classMap } from "lit/directives/class-map.js";
|
|
3
|
+
import componentStyle from "./gauge-radial.css.js";
|
|
2
4
|
import { customElement } from "../../decorator.js";
|
|
3
5
|
import { property } from "lit/decorators.js";
|
|
4
6
|
import { InstrumentState, Priority } from "../types.js";
|
|
5
7
|
import { SetpointMixin } from "../../svghelpers/setpoint-mixin.js";
|
|
6
8
|
import "../../building-blocks/instrument-radial/instrument-radial.js";
|
|
7
9
|
import { TickmarkStyle } from "../watch/tickmark.js";
|
|
10
|
+
import { ReadoutStackVerticalAlignment, ReadoutVariant } from "../readout/readout.js";
|
|
8
11
|
var __defProp = Object.defineProperty;
|
|
9
12
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
10
13
|
var __decorateClass = (decorators, target, key, kind) => {
|
|
@@ -21,6 +24,13 @@ var ObcGaugeRadialType = /* @__PURE__ */ ((ObcGaugeRadialType2) => {
|
|
|
21
24
|
ObcGaugeRadialType2["needle"] = "needle";
|
|
22
25
|
return ObcGaugeRadialType2;
|
|
23
26
|
})(ObcGaugeRadialType || {});
|
|
27
|
+
var GaugeRadialSector = /* @__PURE__ */ ((GaugeRadialSector2) => {
|
|
28
|
+
GaugeRadialSector2["deg270"] = "270";
|
|
29
|
+
GaugeRadialSector2["deg180"] = "180";
|
|
30
|
+
GaugeRadialSector2["deg90Left"] = "90-left";
|
|
31
|
+
GaugeRadialSector2["deg90Right"] = "90-right";
|
|
32
|
+
return GaugeRadialSector2;
|
|
33
|
+
})(GaugeRadialSector || {});
|
|
24
34
|
let ObcGaugeRadial = class extends SetpointMixin(LitElement) {
|
|
25
35
|
constructor() {
|
|
26
36
|
super(...arguments);
|
|
@@ -37,45 +47,166 @@ let ObcGaugeRadial = class extends SetpointMixin(LitElement) {
|
|
|
37
47
|
this.tickmarksInside = false;
|
|
38
48
|
this.tickmarkStyle = TickmarkStyle.regular;
|
|
39
49
|
this.advices = [];
|
|
50
|
+
this.sector = "270";
|
|
51
|
+
this.showReadout = false;
|
|
52
|
+
this.label = "";
|
|
53
|
+
this.unit = "";
|
|
54
|
+
this.fractionDigits = 0;
|
|
55
|
+
this.getAngle = (v) => {
|
|
56
|
+
const { sweep, start } = this.sectorAngles;
|
|
57
|
+
const span = this.maxValue - this.minValue;
|
|
58
|
+
if (!Number.isFinite(span) || span <= 0) {
|
|
59
|
+
return start;
|
|
60
|
+
}
|
|
61
|
+
return (v - this.minValue) / span * sweep + start;
|
|
62
|
+
};
|
|
40
63
|
}
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
64
|
+
get sectorAngles() {
|
|
65
|
+
switch (this.sector) {
|
|
66
|
+
case "180":
|
|
67
|
+
return { sweep: 180, start: -90 };
|
|
68
|
+
case "90-left":
|
|
69
|
+
return { sweep: 90, start: -90 };
|
|
70
|
+
case "90-right":
|
|
71
|
+
return { sweep: 90, start: 0 };
|
|
72
|
+
case "270":
|
|
73
|
+
default:
|
|
74
|
+
return { sweep: 270, start: -135 };
|
|
45
75
|
}
|
|
46
|
-
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Per-edge crop (%) of the shared, origin-centered 448 SVG box each sector
|
|
79
|
+
* shows. All sectors render at the same natural scale, so the dial stays the
|
|
80
|
+
* same size; the sector only windows a different part (270 whole, 180 wide,
|
|
81
|
+
* 90 a quadrant).
|
|
82
|
+
*/
|
|
83
|
+
get sectorClips() {
|
|
84
|
+
switch (this.sector) {
|
|
85
|
+
case "180":
|
|
86
|
+
return { top: 0, bottom: 44, left: 0, right: 0 };
|
|
87
|
+
case "90-left":
|
|
88
|
+
return { top: 0, bottom: 45, left: 0, right: 45 };
|
|
89
|
+
case "90-right":
|
|
90
|
+
return { top: 0, bottom: 45, left: 45, right: 0 };
|
|
91
|
+
case "270":
|
|
92
|
+
default:
|
|
93
|
+
return { top: 0, bottom: 0, left: 0, right: 0 };
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
get isSector90() {
|
|
97
|
+
return this.sector === "90-left" || this.sector === "90-right";
|
|
98
|
+
}
|
|
99
|
+
/** Renders one gauge readout; `withMeta`/`labelOnly` pick parts. */
|
|
100
|
+
renderReadout({
|
|
101
|
+
className,
|
|
102
|
+
variant,
|
|
103
|
+
alignment = ReadoutStackVerticalAlignment.vertical,
|
|
104
|
+
withMeta = true,
|
|
105
|
+
labelOnly = false
|
|
106
|
+
}) {
|
|
107
|
+
const withValue = !labelOnly;
|
|
108
|
+
return html`
|
|
109
|
+
<obc-readout
|
|
110
|
+
class=${className}
|
|
111
|
+
direction="vertical"
|
|
112
|
+
?labelOnly=${labelOnly}
|
|
113
|
+
.variant=${variant}
|
|
114
|
+
.alignment=${alignment}
|
|
115
|
+
.valuePriority=${withValue ? this.priority : void 0}
|
|
116
|
+
.value=${withValue ? this.value : void 0}
|
|
117
|
+
.fractionDigits=${this.fractionDigits}
|
|
118
|
+
.label=${withMeta ? this.label : ""}
|
|
119
|
+
.unit=${withMeta ? this.unit : ""}
|
|
120
|
+
></obc-readout>
|
|
121
|
+
`;
|
|
122
|
+
}
|
|
123
|
+
renderReadouts() {
|
|
124
|
+
if (!this.showReadout) {
|
|
125
|
+
return nothing;
|
|
126
|
+
}
|
|
127
|
+
const isNeedle = this.type === "needle";
|
|
128
|
+
const is90 = this.isSector90;
|
|
129
|
+
const is180 = this.sector === "180";
|
|
130
|
+
if (isNeedle && (is180 || is90)) {
|
|
131
|
+
return nothing;
|
|
132
|
+
}
|
|
133
|
+
if (is90) {
|
|
134
|
+
return this.renderReadout({
|
|
135
|
+
className: "gauge-readout-meta",
|
|
136
|
+
variant: ReadoutVariant.enhanced
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
if (isNeedle || is180) {
|
|
140
|
+
return this.renderReadout({
|
|
141
|
+
className: "gauge-readout-meta",
|
|
142
|
+
variant: ReadoutVariant.stack,
|
|
143
|
+
alignment: ReadoutStackVerticalAlignment.center
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
return html`
|
|
147
|
+
${this.renderReadout({
|
|
148
|
+
className: "gauge-readout-value",
|
|
149
|
+
variant: ReadoutVariant.enhanced,
|
|
150
|
+
withMeta: false
|
|
151
|
+
})}
|
|
152
|
+
${this.label || this.unit ? this.renderReadout({
|
|
153
|
+
className: "gauge-readout-meta",
|
|
154
|
+
variant: ReadoutVariant.stack,
|
|
155
|
+
alignment: ReadoutStackVerticalAlignment.center,
|
|
156
|
+
labelOnly: true
|
|
157
|
+
}) : nothing}
|
|
158
|
+
`;
|
|
47
159
|
}
|
|
48
160
|
render() {
|
|
161
|
+
const clips = this.sectorClips;
|
|
49
162
|
return html`
|
|
50
|
-
<
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
.autoAtSetpoint=${this.autoAtSetpoint}
|
|
60
|
-
.autoAtSetpointDeadband=${this.autoAtSetpointDeadband}
|
|
61
|
-
.animateSetpoint=${this.animateSetpoint}
|
|
62
|
-
.maxValue=${this.maxValue}
|
|
63
|
-
.minValue=${this.minValue}
|
|
64
|
-
.getAngle=${this.getAngle}
|
|
65
|
-
.showLabels=${this.showLabels}
|
|
66
|
-
.primaryTickmarkInterval=${this.primaryTickmarkInterval}
|
|
67
|
-
.secondaryTickmarkInterval=${this.secondaryTickmarkInterval}
|
|
68
|
-
.tertiaryTickmarkInterval=${this.tertiaryTickmarkInterval}
|
|
69
|
-
.type=${this.type}
|
|
70
|
-
.needleType=${this.type}
|
|
71
|
-
.tickmarksInside=${this.tickmarksInside}
|
|
72
|
-
.tickmarkStyle=${this.tickmarkStyle}
|
|
73
|
-
.advices=${this.advices}
|
|
163
|
+
<div
|
|
164
|
+
class=${classMap({
|
|
165
|
+
"gauge-radial-root": true,
|
|
166
|
+
"type-needle": this.type === "needle",
|
|
167
|
+
"sector-180": this.sector === "180",
|
|
168
|
+
"sector-90-left": this.sector === "90-left",
|
|
169
|
+
"sector-90-right": this.sector === "90-right"
|
|
170
|
+
/* deg90Right */
|
|
171
|
+
})}
|
|
74
172
|
>
|
|
75
|
-
|
|
173
|
+
<obc-instrument-radial
|
|
174
|
+
.value=${this.value}
|
|
175
|
+
.state=${this.state}
|
|
176
|
+
.priority=${this.priority}
|
|
177
|
+
.setpoint=${this.setpoint}
|
|
178
|
+
.newSetpoint=${this.newSetpoint}
|
|
179
|
+
.setpointAtZeroDeadband=${this.setpointAtZeroDeadband}
|
|
180
|
+
.setpointOverride=${this.setpointOverride}
|
|
181
|
+
.touching=${this.touching}
|
|
182
|
+
.autoAtSetpoint=${this.autoAtSetpoint}
|
|
183
|
+
.autoAtSetpointDeadband=${this.autoAtSetpointDeadband}
|
|
184
|
+
.animateSetpoint=${this.animateSetpoint}
|
|
185
|
+
.maxValue=${this.maxValue}
|
|
186
|
+
.minValue=${this.minValue}
|
|
187
|
+
.getAngle=${this.getAngle}
|
|
188
|
+
.showLabels=${this.showLabels}
|
|
189
|
+
.primaryTickmarkInterval=${this.primaryTickmarkInterval}
|
|
190
|
+
.secondaryTickmarkInterval=${this.secondaryTickmarkInterval}
|
|
191
|
+
.tertiaryTickmarkInterval=${this.tertiaryTickmarkInterval}
|
|
192
|
+
.type=${this.type}
|
|
193
|
+
.needleType=${this.type}
|
|
194
|
+
.tickmarksInside=${this.tickmarksInside}
|
|
195
|
+
.tickmarkStyle=${this.tickmarkStyle}
|
|
196
|
+
.advices=${this.isSector90 ? [] : this.advices}
|
|
197
|
+
.clipTop=${clips.top}
|
|
198
|
+
.clipBottom=${clips.bottom}
|
|
199
|
+
.clipLeft=${clips.left}
|
|
200
|
+
.clipRight=${clips.right}
|
|
201
|
+
.endLabelsMaxMin=${this.sector === "180"}
|
|
202
|
+
>
|
|
203
|
+
</obc-instrument-radial>
|
|
204
|
+
${this.renderReadouts()}
|
|
205
|
+
</div>
|
|
76
206
|
`;
|
|
77
207
|
}
|
|
78
208
|
};
|
|
209
|
+
ObcGaugeRadial.styles = unsafeCSS(componentStyle);
|
|
79
210
|
__decorateClass([
|
|
80
211
|
property({ type: Number })
|
|
81
212
|
], ObcGaugeRadial.prototype, "value", 2);
|
|
@@ -115,10 +246,26 @@ __decorateClass([
|
|
|
115
246
|
__decorateClass([
|
|
116
247
|
property({ type: Array, attribute: false })
|
|
117
248
|
], ObcGaugeRadial.prototype, "advices", 2);
|
|
249
|
+
__decorateClass([
|
|
250
|
+
property({ type: String, reflect: true })
|
|
251
|
+
], ObcGaugeRadial.prototype, "sector", 2);
|
|
252
|
+
__decorateClass([
|
|
253
|
+
property({ type: Boolean })
|
|
254
|
+
], ObcGaugeRadial.prototype, "showReadout", 2);
|
|
255
|
+
__decorateClass([
|
|
256
|
+
property({ type: String })
|
|
257
|
+
], ObcGaugeRadial.prototype, "label", 2);
|
|
258
|
+
__decorateClass([
|
|
259
|
+
property({ type: String })
|
|
260
|
+
], ObcGaugeRadial.prototype, "unit", 2);
|
|
261
|
+
__decorateClass([
|
|
262
|
+
property({ type: Number })
|
|
263
|
+
], ObcGaugeRadial.prototype, "fractionDigits", 2);
|
|
118
264
|
ObcGaugeRadial = __decorateClass([
|
|
119
265
|
customElement("obc-gauge-radial")
|
|
120
266
|
], ObcGaugeRadial);
|
|
121
267
|
export {
|
|
268
|
+
GaugeRadialSector,
|
|
122
269
|
ObcGaugeRadial,
|
|
123
270
|
ObcGaugeRadialType
|
|
124
271
|
};
|