@oicl/openbridge-webcomponents 0.0.20260407101310 → 0.0.20260407112816
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/building-blocks/instrument-radial/instrument-radial.d.ts +3 -0
- package/dist/building-blocks/instrument-radial/instrument-radial.d.ts.map +1 -1
- package/dist/building-blocks/instrument-radial/instrument-radial.js +50 -22
- package/dist/building-blocks/instrument-radial/instrument-radial.js.map +1 -1
- package/dist/navigation-instruments/compass/arrow.d.ts +1 -1
- package/dist/navigation-instruments/compass/arrow.d.ts.map +1 -1
- package/dist/navigation-instruments/compass/arrow.js +3 -3
- package/dist/navigation-instruments/compass/arrow.js.map +1 -1
- package/dist/navigation-instruments/compass/compass.d.ts +12 -6
- package/dist/navigation-instruments/compass/compass.d.ts.map +1 -1
- package/dist/navigation-instruments/compass/compass.js +29 -24
- package/dist/navigation-instruments/compass/compass.js.map +1 -1
- package/dist/navigation-instruments/compass-flat/compass-flat.d.ts +37 -1
- package/dist/navigation-instruments/compass-flat/compass-flat.d.ts.map +1 -1
- package/dist/navigation-instruments/compass-flat/compass-flat.js +34 -3
- package/dist/navigation-instruments/compass-flat/compass-flat.js.map +1 -1
- package/dist/navigation-instruments/compass-sector/compass-sector.css.js +34 -0
- package/dist/navigation-instruments/compass-sector/compass-sector.css.js.map +1 -0
- package/dist/navigation-instruments/compass-sector/compass-sector.d.ts +101 -0
- package/dist/navigation-instruments/compass-sector/compass-sector.d.ts.map +1 -0
- package/dist/navigation-instruments/compass-sector/compass-sector.js +404 -0
- package/dist/navigation-instruments/compass-sector/compass-sector.js.map +1 -0
- package/dist/navigation-instruments/rate-of-turn/rate-of-turn.controller.d.ts +15 -2
- package/dist/navigation-instruments/rate-of-turn/rate-of-turn.controller.d.ts.map +1 -1
- package/dist/navigation-instruments/rate-of-turn/rate-of-turn.controller.js +50 -18
- package/dist/navigation-instruments/rate-of-turn/rate-of-turn.controller.js.map +1 -1
- package/dist/navigation-instruments/rate-of-turn/rate-of-turn.d.ts +40 -6
- package/dist/navigation-instruments/rate-of-turn/rate-of-turn.d.ts.map +1 -1
- package/dist/navigation-instruments/rate-of-turn/rate-of-turn.js +40 -47
- package/dist/navigation-instruments/rate-of-turn/rate-of-turn.js.map +1 -1
- package/dist/navigation-instruments/rate-of-turn/rot-renderer.d.ts +63 -0
- package/dist/navigation-instruments/rate-of-turn/rot-renderer.d.ts.map +1 -0
- package/dist/navigation-instruments/rate-of-turn/rot-renderer.js +211 -0
- package/dist/navigation-instruments/rate-of-turn/rot-renderer.js.map +1 -0
- package/dist/navigation-instruments/rot-sector/rot-sector.d.ts +10 -4
- package/dist/navigation-instruments/rot-sector/rot-sector.d.ts.map +1 -1
- package/dist/navigation-instruments/rot-sector/rot-sector.js +13 -3
- package/dist/navigation-instruments/rot-sector/rot-sector.js.map +1 -1
- package/dist/navigation-instruments/rudder/rudder.d.ts +4 -0
- package/dist/navigation-instruments/rudder/rudder.d.ts.map +1 -1
- package/dist/navigation-instruments/rudder/rudder.js +55 -19
- package/dist/navigation-instruments/rudder/rudder.js.map +1 -1
- package/dist/navigation-instruments/watch/advice.d.ts +3 -3
- package/dist/navigation-instruments/watch/advice.d.ts.map +1 -1
- package/dist/navigation-instruments/watch/advice.js +68 -16
- package/dist/navigation-instruments/watch/advice.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 +15 -13
- package/dist/navigation-instruments/watch/tickmark.js.map +1 -1
- package/dist/navigation-instruments/watch/watch.d.ts +29 -0
- package/dist/navigation-instruments/watch/watch.d.ts.map +1 -1
- package/dist/navigation-instruments/watch/watch.js +256 -44
- package/dist/navigation-instruments/watch/watch.js.map +1 -1
- package/dist/navigation-instruments/watch-flat/watch-flat.d.ts +29 -1
- package/dist/navigation-instruments/watch-flat/watch-flat.d.ts.map +1 -1
- package/dist/navigation-instruments/watch-flat/watch-flat.js +162 -17
- package/dist/navigation-instruments/watch-flat/watch-flat.js.map +1 -1
- package/dist/svghelpers/arc-frame.d.ts +42 -0
- package/dist/svghelpers/arc-frame.d.ts.map +1 -0
- package/dist/svghelpers/arc-frame.js +123 -0
- package/dist/svghelpers/arc-frame.js.map +1 -0
- package/package.json +1 -1
- package/dist/navigation-instruments/compass/rot.d.ts +0 -4
- package/dist/navigation-instruments/compass/rot.d.ts.map +0 -1
- package/dist/navigation-instruments/compass/rot.js +0 -11
- package/dist/navigation-instruments/compass/rot.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"watch.js","sources":["../../../src/navigation-instruments/watch/watch.ts"],"sourcesContent":["import {\n LitElement,\n PropertyValues,\n SVGTemplateResult,\n html,\n nothing,\n svg,\n unsafeCSS,\n} from 'lit';\nimport {property, state} from 'lit/decorators.js';\nimport {circle} from '../../svghelpers/index.js';\nimport {roundedArch} from '../../svghelpers/roundedArch.js';\nimport {\n cssSafeAngle,\n deriveRadialSetpointConfig,\n drawSetpointMarker,\n getSetpointAnimationDurationMs,\n getSetpointOutwardOffset,\n RADIAL_SETPOINT_RADIUS,\n SetpointVisualState,\n SETPOINT_ANIMATION_CSS_VAR,\n SETPOINT_ANIMATION_DURATION_DEFAULT,\n} from '../../svghelpers/setpoint.js';\nimport {InstrumentState, Priority} from '../types.js';\nimport compentStyle from './watch.css?inline';\nimport {ResizeController} from '@lit-labs/observers/resize-controller.js';\nimport {adviceMask, AngleAdviceRaw, renderAdvice} from './advice.js';\nimport {Tickmark, TickmarkStyle, tickmark} from './tickmark.js';\nexport {TickmarkStyle};\nimport {\n renderLabels,\n renderNorthArrow,\n getLabelPositions,\n LabelPosition,\n} from './label.js';\nimport {VesselImage, VesselImageSize, vesselImages} from './vessel.js';\nimport {renderCurrent, renderWind} from './environment.js';\nimport {customElement} from '../../decorator.js';\nexport {VesselImage, VesselImageSize};\n\nexport enum WatchCircleType {\n single = 'single',\n double = 'double',\n doubleThin = 'doubleThin',\n triple = 'triple',\n}\n\nexport interface WatchArea {\n startAngle: number;\n endAngle: number;\n roundOutsideCut: boolean;\n roundInsideCut: boolean;\n}\n\nexport interface WatchBarArea {\n startAngle: number;\n endAngle: number;\n fillColor: string;\n}\n\nexport interface WatchNeedle {\n angle: number;\n fillColor: string;\n strokeColor: string;\n}\n\nexport interface WatchVessel {\n size: VesselImageSize;\n transform: string;\n vesselImage: VesselImage;\n}\n\nexport const OUTER_RING_RADIUS = 368 / 2;\nconst RING2_RADIUS = 320 / 2;\nconst RING3_RADIUS = 224 / 2;\nconst RING3B_RADIUS = 272 / 2;\nconst RING4_RADIUS = 176 / 2;\n\nconst RADIAL_SETPOINT_INWARD_ADJUST = 4;\n\n/**\n * `<obc-watch>` - Core SVG renderer for circular/radial watch-based instruments.\n *\n * This component renders all circular instrument elements including rings, tickmarks,\n * bar areas, needles, advices, setpoints, vessel images, and environmental indicators\n * (wind/current). It serves as the foundation for compass, heading, rudder, speed-gauge,\n * and other radial navigation instruments.\n *\n * ## Setpoint Behavior\n *\n * The setpoint marker visual state is derived from the combination of `atAngleSetpoint`,\n * `angleSetpoint`, and `angleSetpointAtZeroDeadband` properties:\n *\n * - **notEqual**: Value differs from setpoint (triangular marker, offset outward)\n * - **equal**: Value matches setpoint (line marker, sits on ring)\n * - **equalZero**: Value matches setpoint at zero angle (double-line marker, offset outward)\n * - **focus**: User is actively adjusting via `newAngleSetpoint` - shows focus visual state\n *\n * ## newAngleSetpoint Pattern\n *\n * When `newAngleSetpoint` is defined, TWO setpoint markers are rendered:\n * 1. Original marker at `angleSetpoint` - dimmed (0.75 opacity)\n * 2. New marker at `newAngleSetpoint` - focus visual state, full opacity\n *\n * This enables the \"adjustment preview\" UX where users can see both the current\n * and proposed setpoint positions simultaneously.\n *\n * The `RADIAL_SETPOINT_INWARD_ADJUST` constant (4px) fine-tunes radial setpoint positioning\n * to match Figma designs, applied on top of visual state offsets from setpoint.ts.\n *\n * The `colorMode` property allows overriding the derived color mode (enhanced for enhanced priority,\n * regular for other states).\n *\n * ## Setpoint Animation (`animateSetpoint`)\n *\n * When `animateSetpoint` is true and a confirm occurs (`newAngleSetpoint` → `undefined`):\n * - The original setpoint slides to the new position via CSS transition\n * - The departing new-setpoint marker fades out\n * - Angular transitions always take the shortest path via accumulated\n * CSS-safe angles (`cssSafeAngle()`), so even 350° → 10° animates +20°\n *\n * Duration: `var(--setpoint-animation-duration, 300ms)`\n *\n * Internally, `_departingNewAngleSetpoint` captures the departing angle during confirm\n * fade-out and `_animationTimer` auto-clears it after the animation duration.\n * `_setpointCssAngle` tracks the accumulated CSS angle to avoid long-way-around\n * transitions across the 0°/360° boundary.\n *\n * @property {InstrumentState} state - Instrument state (active, loading, off)\n * @property {Priority} priority - Color priority (enhanced = blue palette, regular = gray palette)\n * @property {number|undefined} angleSetpoint - Setpoint angle in degrees (0° = 12 o'clock)\n * @property {number|undefined} newAngleSetpoint - New setpoint being adjusted (focus mode)\n * @property {boolean} atAngleSetpoint - Whether value matches setpoint (within deadband)\n * @property {number} angleSetpointAtZeroDeadband - Deadband for zero detection (default 0.5°)\n * @property {boolean} setpointOverride - Override to derive setpoint color from priority regardless of state\n */\n@customElement('obc-watch')\nexport class ObcWatch extends LitElement {\n private _setpointId = `watch-setpoint-${Math.random().toString(36).slice(2, 9)}`;\n private _newSetpointId = `watch-new-setpoint-${Math.random().toString(36).slice(2, 9)}`;\n\n @property({type: String}) state: InstrumentState = InstrumentState.active;\n @property({type: String}) priority: Priority = Priority.regular;\n @property({type: String}) watchCircleType: WatchCircleType =\n WatchCircleType.single;\n @property({type: Boolean}) northArrow: boolean = false;\n @property({type: Number}) angleSetpoint: number | undefined;\n @property({type: Number}) newAngleSetpoint: number | undefined;\n @property({type: Boolean}) atAngleSetpoint: boolean = false;\n @property({type: Number}) angleSetpointAtZeroDeadband: number = 0.5;\n @property({type: Boolean}) setpointOverride: boolean = false;\n @property({type: Boolean}) touching: boolean = false;\n\n @property({type: Boolean}) animateSetpoint: boolean = false;\n\n @state() private _departingNewAngleSetpoint: number | undefined;\n private _animationTimer?: ReturnType<typeof setTimeout>;\n\n /**\n * Accumulated CSS-safe angle for the original setpoint marker.\n * Ensures CSS rotate() transitions always take the shortest path,\n * even across the 0°/360° boundary.\n */\n private _setpointCssAngle: number = 0;\n\n /** Whether the setpoint CSS angle has been initialised (to skip transition on first render). */\n private _setpointCssAngleInit = false;\n @property({type: Number}) padding: number | undefined;\n @property({type: Array, attribute: false}) areas: WatchArea[] = [];\n @property({type: Array, attribute: false}) barAreas: WatchBarArea[] = [];\n @property({type: Array, attribute: false}) needles: WatchNeedle[] = [];\n @property({type: Array, attribute: false}) tickmarks: Tickmark[] = [];\n @property({type: Boolean}) tickmarksInside: boolean = false;\n @property({type: String}) tickmarkStyle: TickmarkStyle =\n TickmarkStyle.regular;\n @property({type: Array, attribute: false}) advices: AngleAdviceRaw[] = [];\n @property({type: Boolean}) crosshairEnabled: boolean = false;\n @property({type: Boolean}) showLabels: boolean = false;\n @property({type: Array, attribute: false}) vessels: WatchVessel[] = [];\n @property({type: Number}) wind: number | null = null;\n @property({type: Number}) windFromDirectionDeg: number | null = null;\n @property({type: Number}) windSymbolRadius: number | null = null;\n @property({type: String}) windColor: string | undefined;\n @property({type: Number}) current: number | null = null;\n @property({type: Number}) currentFromDirectionDeg: number | null = null;\n @property({type: Number}) currentSymbolRadius: number | null = null;\n @property({type: String}) currentColor: string | undefined;\n @property({type: Boolean}) starboardPortIndicator: boolean = false;\n @property({type: Number}) clipTop: number = 0; // in percent of height\n @property({type: Number}) clipBottom: number = 0; // in percent of height\n @property({type: Number}) scaleWindIcon: number = 1;\n @property({type: Number}) rotation: number | undefined;\n\n // @ts-expect-error TS6133: The controller ensures that the render\n // function is called on resize of the element\n private _resizeController = new ResizeController(this, {});\n\n override willUpdate(changed: PropertyValues): void {\n super.willUpdate(changed);\n\n // Detect confirm: newAngleSetpoint was defined, now undefined\n if (changed.has('newAngleSetpoint') && this.animateSetpoint) {\n const prev = changed.get('newAngleSetpoint') as number | undefined;\n if (prev !== undefined && this.newAngleSetpoint === undefined) {\n this._departingNewAngleSetpoint = prev;\n clearTimeout(this._animationTimer);\n const duration = getSetpointAnimationDurationMs(this);\n this._animationTimer = setTimeout(() => {\n this._departingNewAngleSetpoint = undefined;\n }, duration);\n }\n }\n }\n\n override disconnectedCallback(): void {\n super.disconnectedCallback();\n clearTimeout(this._animationTimer);\n }\n\n private get innerRingRadius(): number {\n if (this.watchCircleType === WatchCircleType.single) {\n return RING2_RADIUS;\n } else if (this.watchCircleType === WatchCircleType.double) {\n return RING3_RADIUS;\n } else if (this.watchCircleType === WatchCircleType.doubleThin) {\n return RING3B_RADIUS;\n } else if (this.watchCircleType === WatchCircleType.triple) {\n return RING4_RADIUS;\n }\n throw new Error(`Invalid watch circle type: ${this.watchCircleType}`);\n }\n\n private watchCircle(): SVGTemplateResult | SVGTemplateResult[] {\n const rings = [];\n if (this.state !== InstrumentState.off) {\n rings.push(svg`\n <circle\n cx=\"0\"\n cy=\"0\"\n r=\"172\"\n stroke=\"var(--instrument-frame-primary-color)\"\n fill=\"none\"\n stroke-width=\"24\"\n />`);\n\n if (this.watchCircleType !== WatchCircleType.single) {\n const r1 = RING2_RADIUS;\n const r2 =\n this.watchCircleType === WatchCircleType.doubleThin\n ? RING3B_RADIUS\n : RING3_RADIUS;\n const r = (r1 + r2) / 2;\n const strokeWidth = r1 - r2;\n rings.push(\n svg`\n <circle cx=\"0\" cy=\"0\" r=${r} stroke=\"var(--instrument-frame-secondary-color)\" stroke-width=${strokeWidth} fill=\"none\" />\n <circle cx=\"0\" cy=\"0\" r=${r1} stroke=\"var(--instrument-frame-secondary-color)\" stroke-width=\"1\" fill=\"none\" vector-effect=\"non-scaling-stroke\" />\n <circle cx=\"0\" cy=\"0\" r=${r2} stroke=\"var(--instrument-frame-secondary-color)\" stroke-width=\"1\" fill=\"none\" vector-effect=\"non-scaling-stroke\" />\n `\n );\n }\n if (this.watchCircleType === WatchCircleType.triple) {\n const r1 = RING3_RADIUS;\n const r2 = RING4_RADIUS;\n const r = (r1 + r2) / 2;\n const strokeWidth = r1 - r2;\n rings.push(\n svg`<circle cx=\"0\" cy=\"0\" r=${r} stroke=\"var(--instrument-frame-primary-color)\" stroke-width=${strokeWidth} fill=\"none\" />`\n );\n }\n }\n\n let result = rings;\n if (this.areas.length > 0) {\n const areas = this.areas.map((area) => {\n const svgPath = roundedArch({\n startAngle: area.startAngle,\n endAngle: area.endAngle,\n R: OUTER_RING_RADIUS,\n r: this.innerRingRadius,\n roundOutsideCut: area.roundOutsideCut,\n roundInsideCut: area.roundInsideCut,\n });\n return svgPath;\n });\n const mask = svg`<mask id=\"cutMask\">\n <rect x=\"-200\" y=\"-200\" width=\"400\" height=\"400\" fill=\"black\" />\n ${areas.map((area) => svg`<path d=${area} fill=\"white\" vector-effect=\"non-scaling-stroke\" stroke=\"white\" stroke-width=\"1\"/>`)}\n </mask>`;\n result = [mask, svg`<g mask=\"url(#cutMask)\">${rings}</g>`];\n areas.forEach((area) => {\n result.push(\n svg`<path d=${area} fill=\"none\" stroke=\"var(--instrument-frame-tertiary-color)\" vector-effect=\"non-scaling-stroke\"/>`\n );\n });\n } else {\n if (this.state !== InstrumentState.off) {\n result.push(\n circle('outerRing', {\n radius: 368 / 2,\n strokeWidth: 1,\n strokeColor: 'var(--instrument-frame-tertiary-color)',\n strokePosition: 'center',\n fillColor: 'none',\n })\n );\n\n result.push(svg`\n ${circle('innerRing', {\n radius: this.innerRingRadius,\n strokeWidth: 1,\n strokeColor: 'var(--instrument-frame-tertiary-color)',\n strokePosition: 'center',\n fillColor: 'none',\n })}\n `);\n } else {\n result.push(svg`\n ${circle('innerRing', {\n radius: OUTER_RING_RADIUS,\n strokeWidth: 1,\n strokeColor: 'var(--instrument-frame-tertiary-color)',\n strokePosition: 'center',\n fillColor: 'none',\n })}\n `);\n }\n }\n return result;\n }\n\n private renderCrosshair(\n radius: number,\n labelKnockouts?: {\n positions: LabelPosition[];\n rotation: number | undefined;\n scale: number;\n /** Inner ring radius – crosshair is hidden between labelRadius and this value. */\n innerRingRadius: number;\n }\n ): SVGTemplateResult {\n const hasMask = labelKnockouts && labelKnockouts.positions.length > 0;\n\n // Radius at which labels sit (distance from centre).\n // Any position is equally valid — they're all at the same radial distance.\n const labelRadius = hasMask\n ? Math.max(\n ...labelKnockouts!.positions.map((l) =>\n Math.abs(l.x !== 0 ? l.x : l.y)\n )\n )\n : 0;\n // Small extra padding so the crosshair doesn't start/end right at the\n // label edge — use the same visual pad as the letter knockouts.\n const ringGapPad = hasMask ? 3 / labelKnockouts!.scale : 0;\n\n return svg`\n ${\n hasMask\n ? svg`\n <defs>\n <mask\n id=\"crosshair-label-mask\"\n maskUnits=\"userSpaceOnUse\"\n x=\"-${radius}\" y=\"-${radius}\"\n width=\"${radius * 2}\" height=\"${radius * 2}\"\n >\n <rect x=\"-${radius}\" y=\"-${radius}\" width=\"${radius * 2}\" height=\"${radius * 2}\" fill=\"white\"/>\n <!-- Annular ring knockout: hide crosshair between labels and inner ring -->\n <circle cx=\"0\" cy=\"0\" r=\"${labelKnockouts!.innerRingRadius}\" fill=\"black\"/>\n <circle cx=\"0\" cy=\"0\" r=\"${labelRadius - ringGapPad}\" fill=\"white\"/>\n <!-- Per-label rectangular knockouts -->\n ${labelKnockouts!.positions.map((l) => {\n const fontSize = 12 / labelKnockouts!.scale;\n const pad = 3 / labelKnockouts!.scale;\n const size = fontSize + pad * 2;\n return svg`\n <rect\n x=\"${l.x - size / 2}\" y=\"${l.y - size / 2}\"\n width=\"${size}\" height=\"${size}\"\n fill=\"black\"\n transform=\"rotate(${-(labelKnockouts!.rotation ?? 0)})\"\n transform-origin=\"${l.x} ${l.y}\"\n />\n `;\n })}\n </mask>\n </defs>`\n : nothing\n }\n <g mask=${hasMask ? 'url(#crosshair-label-mask)' : nothing}>\n <line\n x1=\"-${radius}\"\n y1=\"0\"\n x2=\"${radius}\"\n y2=\"0\"\n stroke=\"var(--instrument-frame-tertiary-color)\"\n stroke-width=\"1\"\n vector-effect=\"non-scaling-stroke\"\n />\n <line\n x1=\"0\"\n y1=\"-${radius}\"\n x2=\"0\"\n y2=\"${radius}\"\n stroke=\"var(--instrument-frame-tertiary-color)\"\n stroke-width=\"1\"\n vector-effect=\"non-scaling-stroke\"\n />\n </g>\n `;\n }\n\n private renderBars(): SVGTemplateResult[] | typeof nothing {\n if (this.barAreas.length === 0) {\n return nothing;\n }\n return this.barAreas.map((bar, index) => {\n const startAngle = Math.min(bar.startAngle, bar.endAngle);\n const endAngle = Math.max(bar.startAngle, bar.endAngle);\n const arc = roundedArch({\n r: RING3_RADIUS,\n R: RING2_RADIUS,\n startAngle: startAngle,\n endAngle: endAngle,\n roundInsideCut: false,\n roundOutsideCut: false,\n });\n // The mask is a sector to cut out the stroke on the start and end of the bar\n const mask = svg`<mask id=\"barMask-${index}\">\n <rect x=\"-200\" y=\"-200\" width=\"400\" height=\"400\" fill=\"black\" />\n <path d=${roundedArch({\n r: 1,\n R: 200,\n startAngle: startAngle,\n endAngle: endAngle,\n roundInsideCut: false,\n roundOutsideCut: false,\n })} fill=\"white\" />\n </mask>`;\n return svg`\n ${mask}\n <g mask=\"url(#cutMask)\">\n <path \n d=${arc} \n fill=${bar.fillColor} \n stroke=${bar.fillColor} \n stroke-width=\"1\" \n vector-effect=\"non-scaling-stroke\" \n mask=\"url(#barMask-${index})\" \n />\n </g>\n `;\n });\n }\n\n private renderNeedles(): SVGTemplateResult[] | typeof nothing {\n if (this.needles.length === 0) {\n return nothing;\n }\n return this.needles.map((needle) => {\n return svg`\n <rect \n transform=\"rotate(${needle.angle})\" \n x=\"-4\" y=\"-160\" width=\"8\" height=\"48\" rx=\"4\" \n fill=${needle.fillColor} \n stroke=${needle.strokeColor}\n stroke-width=\"1\"\n vector-effect=\"non-scaling-stroke\"\n paint-order=\"stroke fill\"\n />\n `;\n });\n }\n\n private getScale({width, height}: {width: number; height: number}): number {\n let clientWidth = this.clientWidth;\n let clientHeight = this.clientHeight;\n if (clientWidth === 0 || clientHeight === 0) {\n const box = this.parentElement?.getBoundingClientRect();\n if (box) {\n clientWidth = box.width;\n clientHeight = box.height;\n }\n }\n const scale = Math.min(clientWidth / width, clientHeight / height);\n if (scale === Infinity || scale < 0) {\n throw new Error('Watch scale is not valid');\n }\n return scale;\n }\n\n private getPadding(): number {\n if (this.padding !== undefined) {\n return this.padding;\n }\n const hasTickmarksWithText =\n this.tickmarks.length > 0 &&\n this.tickmarks.some((t) => t.text !== undefined);\n if (hasTickmarksWithText && !this.tickmarksInside) {\n return 24 * 2.5;\n }\n return 24;\n }\n\n override render() {\n const width = (176 + this.getPadding()) * 2;\n const height = width * (1 - this.clipTop / 100 - this.clipBottom / 100);\n const top = -width / 2 + (width * this.clipTop) / 100;\n const scale = this.getScale({width, height});\n const viewBox = `-${width / 2} ${top} ${width} ${height}`;\n const angleSetpoint = this.renderSetpoint();\n const textRadius = this.tickmarksInside\n ? this.innerRingRadius\n : OUTER_RING_RADIUS;\n const maxDigits = Math.max(\n ...this.tickmarks.map((t) => t.text?.length ?? 0)\n );\n const tickmarks = this.tickmarks.map((t) =>\n tickmark(t.angle, {\n size: t.type,\n style: this.tickmarkStyle,\n scale,\n text: this.showLabels ? undefined : t.text,\n inside: this.tickmarksInside,\n textRadius,\n rotation: this.rotation,\n maxDigits,\n color: t.color,\n })\n );\n const advices = this.advices\n ? this.advices.map((a) => renderAdvice(a))\n : nothing;\n\n // Compute label positions once – used for both rendering and crosshair knockout.\n const insideLabels = this.tickmarksInside && this.showLabels;\n const includeNorth = !this.northArrow;\n const labelPositions = this.showLabels\n ? getLabelPositions({\n scale,\n inside: this.tickmarksInside,\n innerRadius: this.innerRingRadius,\n includeNorth,\n })\n : undefined;\n\n const labels = labelPositions\n ? renderLabels({\n scale,\n rotation: this.rotation,\n inside: this.tickmarksInside,\n innerRadius: this.innerRingRadius,\n includeNorth,\n })\n : nothing;\n const northArrowEl = this.northArrow\n ? renderNorthArrow({\n scale,\n rotation: this.rotation,\n inside: this.tickmarksInside,\n })\n : nothing;\n const wind =\n this.wind != null && this.windFromDirectionDeg != null\n ? svg`<g transform=\"scale(${this.scaleWindIcon})\">${renderWind({\n wind: this.wind,\n fromDirectionDeg: this.windFromDirectionDeg,\n radius: this.windSymbolRadius ?? 192,\n color: this.windColor,\n })}</g>`\n : nothing;\n const current =\n this.current != null && this.currentFromDirectionDeg != null\n ? renderCurrent({\n current: this.current,\n fromDirectionDeg: this.currentFromDirectionDeg,\n radius: this.currentSymbolRadius ?? 192,\n color: this.currentColor,\n })\n : nothing;\n return html`\n <svg\n width=\"100%\"\n height=\"100%\"\n viewBox=${viewBox}\n style=\"--scale: ${scale}\"\n transform=\"rotate(${this.rotation ?? 0})\"\n >\n ${this.watchCircle()} ${this.renderBars()}\n ${this.crosshairEnabled\n ? this.renderCrosshair(\n 184,\n insideLabels && labelPositions\n ? {\n positions: labelPositions,\n rotation: this.rotation,\n scale,\n innerRingRadius: this.innerRingRadius,\n }\n : undefined\n )\n : nothing}\n ${northArrowEl} ${this.renderStarboardPortIndicator()} ${current}\n ${wind} ${tickmarks} ${advices} ${angleSetpoint} ${labels}\n ${this.renderVesselImage()} ${this.renderNeedles()}\n </svg>\n `;\n }\n\n private renderSetpoint(): SVGTemplateResult | typeof nothing {\n if (this.angleSetpoint === undefined) {\n return nothing;\n }\n\n const derived = deriveRadialSetpointConfig({\n state: this.state,\n priority: this.priority,\n atSetpoint: this.atAngleSetpoint,\n angleSetpoint: this.angleSetpoint,\n setpointAtZeroDeadband: this.angleSetpointAtZeroDeadband,\n newAngleSetpoint: this.newAngleSetpoint,\n touching: this.touching,\n setpointOverride: this.setpointOverride,\n });\n\n const {visualState, colorMode, disabled, hasNewSetpoint} = derived;\n\n const outwardOffset = getSetpointOutwardOffset(visualState);\n const radius =\n RADIAL_SETPOINT_RADIUS + outwardOffset - RADIAL_SETPOINT_INWARD_ADJUST;\n\n // Render original setpoint marker (dimmed when newAngleSetpoint is active)\n const opacity = hasNewSetpoint ? 0.75 : 1;\n const originalMarker = drawSetpointMarker({\n visualState,\n colorMode,\n disabled,\n id: this._setpointId,\n });\n\n const animate = this.animateSetpoint;\n const hasDeparting = this._departingNewAngleSetpoint !== undefined;\n\n // Compute CSS-safe accumulated angle so transitions always take the short path\n const rawAngle = this.angleSetpoint + 90;\n if (!this._setpointCssAngleInit) {\n // First render: set angle without transition\n this._setpointCssAngle = rawAngle;\n this._setpointCssAngleInit = true;\n } else {\n this._setpointCssAngle = cssSafeAngle(this._setpointCssAngle, rawAngle);\n }\n\n // Use CSS style transform when animating for smooth transition\n const originalSetpoint = animate\n ? svg`\n <g style=\"transform: rotate(${this._setpointCssAngle}deg) translateX(${-radius}px) rotate(270deg); opacity: ${opacity}; transition: transform var(${SETPOINT_ANIMATION_CSS_VAR}, ${SETPOINT_ANIMATION_DURATION_DEFAULT}) ease-out, opacity var(${SETPOINT_ANIMATION_CSS_VAR}, ${SETPOINT_ANIMATION_DURATION_DEFAULT}) ease-out;\">\n ${originalMarker}\n </g>\n `\n : svg`\n <g transform=\"rotate(${this.angleSetpoint + 90}) translate(${-radius}, 0) rotate(270)\" opacity=\"${opacity}\">\n ${originalMarker}\n </g>\n `;\n\n // Render newAngleSetpoint in focus state (always on top)\n // OR render departing newAngleSetpoint during confirm fade-out\n if (hasNewSetpoint || hasDeparting) {\n const isActive = hasNewSetpoint;\n const newAngle = isActive\n ? this.newAngleSetpoint!\n : this._departingNewAngleSetpoint!;\n const targetOpacity = isActive ? 1 : 0;\n\n const focusOutwardOffset = getSetpointOutwardOffset(\n SetpointVisualState.focus\n );\n const focusRadius =\n RADIAL_SETPOINT_RADIUS +\n focusOutwardOffset -\n RADIAL_SETPOINT_INWARD_ADJUST;\n\n const newMarker = drawSetpointMarker({\n visualState: SetpointVisualState.focus,\n colorMode,\n disabled: false, // newSetpoint is never disabled\n id: this._newSetpointId,\n });\n\n if (animate) {\n const duration = `var(${SETPOINT_ANIMATION_CSS_VAR}, ${SETPOINT_ANIMATION_DURATION_DEFAULT})`;\n return svg`\n ${originalSetpoint}\n <g style=\"transform: rotate(${newAngle + 90}deg) translateX(${-focusRadius}px) rotate(270deg); opacity: ${targetOpacity}; transition: opacity ${duration} ease-out;\">\n ${newMarker}\n </g>\n `;\n }\n\n return svg`\n ${originalSetpoint}\n <g transform=\"rotate(${newAngle + 90}) translate(${-focusRadius}, 0) rotate(270)\" opacity=\"${targetOpacity}\">\n ${newMarker}\n </g>\n `;\n }\n\n return originalSetpoint;\n }\n\n private renderVesselImage(): SVGTemplateResult[] | typeof nothing {\n if (this.vessels.length === 0) {\n return nothing;\n }\n\n return this.vessels.map((v) => {\n let size;\n switch (v.size) {\n case VesselImageSize.large:\n size = 224;\n break;\n case VesselImageSize.medium:\n size = 160;\n break;\n default:\n size = 100;\n }\n\n const scale = size / 160;\n return svg`<g style=\"transform: ${v.transform} scale(${scale}) translate(-80px, -80px) \">${vesselImages[v.vesselImage]}</g>`;\n });\n }\n\n private renderStarboardPortIndicator(): SVGTemplateResult[] | typeof nothing {\n if (!this.starboardPortIndicator) {\n return nothing;\n }\n return [\n adviceMask(\n 0,\n 180,\n 'var(--instrument-starboard-secondary-color)',\n 'var(--instrument-starboard-secondary-color)'\n ),\n adviceMask(\n 180,\n 360,\n 'var(--instrument-port-secondary-color)',\n 'var(--instrument-port-secondary-color)'\n ),\n ];\n }\n\n static override styles = unsafeCSS(compentStyle);\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'obc-watch': ObcWatch;\n }\n}\n"],"names":["WatchCircleType"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"watch.js","sources":["../../../src/navigation-instruments/watch/watch.ts"],"sourcesContent":["import {\n LitElement,\n PropertyValues,\n SVGTemplateResult,\n html,\n nothing,\n svg,\n unsafeCSS,\n} from 'lit';\nimport {property, state} from 'lit/decorators.js';\nimport {circle} from '../../svghelpers/index.js';\nimport {roundedArch} from '../../svghelpers/roundedArch.js';\nimport {\n cssSafeAngle,\n deriveRadialSetpointConfig,\n drawSetpointMarker,\n getSetpointAnimationDurationMs,\n getSetpointOutwardOffset,\n RADIAL_SETPOINT_RADIUS,\n SetpointVisualState,\n SETPOINT_ANIMATION_CSS_VAR,\n SETPOINT_ANIMATION_DURATION_DEFAULT,\n} from '../../svghelpers/setpoint.js';\nimport {InstrumentState, Priority} from '../types.js';\nimport compentStyle from './watch.css?inline';\nimport {ResizeController} from '@lit-labs/observers/resize-controller.js';\nimport {adviceMask, AngleAdviceRaw, renderAdvice} from './advice.js';\nimport {Tickmark, TickmarkStyle, tickmark} from './tickmark.js';\nexport {TickmarkStyle};\nimport {\n RotType,\n RotPosition,\n renderRotDots,\n renderRotBarStatic,\n renderRotBarDots,\n shortestAngularDeltaDeg,\n} from '../rate-of-turn/rot-renderer.js';\nexport {RotType, RotPosition};\nimport {\n RateOfTurnController,\n disposeRotController,\n} from '../rate-of-turn/rate-of-turn.controller.js';\nimport {\n renderLabels,\n renderNorthArrow,\n getLabelPositions,\n LabelPosition,\n} from './label.js';\nimport {VesselImage, VesselImageSize, vesselImages} from './vessel.js';\nimport {renderCurrent, renderWind} from './environment.js';\nimport {customElement} from '../../decorator.js';\nimport {\n computeZoomToFitArcFrame,\n type ZoomToFitArcFrame,\n} from '../../svghelpers/arc-frame.js';\nexport {VesselImage, VesselImageSize};\n\nexport enum WatchCircleType {\n single = 'single',\n double = 'double',\n doubleThin = 'doubleThin',\n triple = 'triple',\n}\n\nexport interface WatchArea {\n startAngle: number;\n endAngle: number;\n roundOutsideCut: boolean;\n roundInsideCut: boolean;\n}\n\nexport interface WatchBarArea {\n startAngle: number;\n endAngle: number;\n fillColor: string;\n}\n\nexport interface WatchNeedle {\n angle: number;\n fillColor: string;\n strokeColor: string;\n}\n\nexport interface WatchVessel {\n size: VesselImageSize;\n transform: string;\n vesselImage: VesselImage;\n}\n\nexport const OUTER_RING_RADIUS = 368 / 2;\nconst RING2_RADIUS = 320 / 2;\nconst RING3_RADIUS = 224 / 2;\nconst RING3B_RADIUS = 272 / 2;\nconst RING4_RADIUS = 176 / 2;\n\nexport function innerRingRadiusFor(type: WatchCircleType): number {\n switch (type) {\n case WatchCircleType.single:\n return RING2_RADIUS;\n case WatchCircleType.double:\n return RING3_RADIUS;\n case WatchCircleType.doubleThin:\n return RING3B_RADIUS;\n case WatchCircleType.triple:\n return RING4_RADIUS;\n default:\n throw new Error(`Unknown WatchCircleType: ${type as string}`);\n }\n}\n\nconst RADIAL_SETPOINT_INWARD_ADJUST = 4;\n\n/**\n * `<obc-watch>` - Core SVG renderer for circular/radial watch-based instruments.\n *\n * This component renders all circular instrument elements including rings, tickmarks,\n * bar areas, needles, advices, setpoints, vessel images, and environmental indicators\n * (wind/current). It serves as the foundation for compass, heading, rudder, speed-gauge,\n * and other radial navigation instruments.\n *\n * ## Setpoint Behavior\n *\n * The setpoint marker visual state is derived from the combination of `atAngleSetpoint`,\n * `angleSetpoint`, and `angleSetpointAtZeroDeadband` properties:\n *\n * - **notEqual**: Value differs from setpoint (triangular marker, offset outward)\n * - **equal**: Value matches setpoint (line marker, sits on ring)\n * - **equalZero**: Value matches setpoint at zero angle (double-line marker, offset outward)\n * - **focus**: User is actively adjusting via `newAngleSetpoint` - shows focus visual state\n *\n * ## newAngleSetpoint Pattern\n *\n * When `newAngleSetpoint` is defined, TWO setpoint markers are rendered:\n * 1. Original marker at `angleSetpoint` - dimmed (0.75 opacity)\n * 2. New marker at `newAngleSetpoint` - focus visual state, full opacity\n *\n * This enables the \"adjustment preview\" UX where users can see both the current\n * and proposed setpoint positions simultaneously.\n *\n * The `RADIAL_SETPOINT_INWARD_ADJUST` constant (4px) fine-tunes radial setpoint positioning\n * to match Figma designs, applied on top of visual state offsets from setpoint.ts.\n *\n * The `colorMode` property allows overriding the derived color mode (enhanced for enhanced priority,\n * regular for other states).\n *\n * ## Setpoint Animation (`animateSetpoint`)\n *\n * When `animateSetpoint` is true and a confirm occurs (`newAngleSetpoint` → `undefined`):\n * - The original setpoint slides to the new position via CSS transition\n * - The departing new-setpoint marker fades out\n * - Angular transitions always take the shortest path via accumulated\n * CSS-safe angles (`cssSafeAngle()`), so even 350° → 10° animates +20°\n *\n * Duration: `var(--setpoint-animation-duration, 300ms)`\n *\n * Internally, `_departingNewAngleSetpoint` captures the departing angle during confirm\n * fade-out and `_animationTimer` auto-clears it after the animation duration.\n * `_setpointCssAngle` tracks the accumulated CSS angle to avoid long-way-around\n * transitions across the 0°/360° boundary.\n *\n * @property {InstrumentState} state - Instrument state (active, loading, off)\n * @property {Priority} priority - Color priority (enhanced = blue palette, regular = gray palette)\n * @property {number|undefined} angleSetpoint - Setpoint angle in degrees (0° = 12 o'clock)\n * @property {number|undefined} newAngleSetpoint - New setpoint being adjusted (focus mode)\n * @property {boolean} atAngleSetpoint - Whether value matches setpoint (within deadband)\n * @property {number} angleSetpointAtZeroDeadband - Deadband for zero detection (default 0.5°)\n * @property {boolean} setpointOverride - Override to derive setpoint color from priority regardless of state\n * @property {RotType|undefined} rotType - ROT visualization type: `'dots'` (spinning dots) or `'bar'` (arc bar with clipped dots). Undefined hides the ROT layer.\n * @property {RotPosition} rotPosition - Track on which ROT elements are placed: `'scale'` (on the outer ring) or `'innerCircle'` (default, inside the inner ring)\n * @property {number} rotStartAngle - Start angle of the ROT bar arc in degrees (0° = 12 o'clock, clockwise). Only used when `rotType` is `'bar'`.\n * @property {number} rotEndAngle - End angle of the ROT bar arc in degrees. The bar is hidden when the difference from `rotStartAngle` is less than 0.1°.\n * @property {Priority|undefined} rotPriority - Override priority for ROT color derivation. When set, ROT colors use this instead of the main `priority`. Useful when the ROT element has independent priority (e.g. compass per-element priority).\n * @property {number} rotationsPerMinute - Spin speed of the ROT dot ring in rotations per minute. Sign controls direction (positive = clockwise).\n * @property {ZoomToFitArcFrame|undefined} arcFrame - Pre-computed zoom-to-fit arc frame. When set, the watch skips its own `computeZoomToFitArcFrame()` call and uses these values directly. Consumer instruments (e.g. rudder, instrument-radial) should compute the frame once and pass it here to avoid redundant computation.\n */\n@customElement('obc-watch')\nexport class ObcWatch extends LitElement {\n private _setpointId = `watch-setpoint-${Math.random().toString(36).slice(2, 9)}`;\n private _newSetpointId = `watch-new-setpoint-${Math.random().toString(36).slice(2, 9)}`;\n\n @property({type: String}) state: InstrumentState = InstrumentState.active;\n @property({type: String}) priority: Priority = Priority.regular;\n @property({type: String}) watchCircleType: WatchCircleType =\n WatchCircleType.single;\n @property({type: Boolean}) northArrow: boolean = false;\n @property({type: Boolean}) northArrowInside: boolean | undefined;\n @property({type: Number}) angleSetpoint: number | undefined;\n @property({type: Number}) newAngleSetpoint: number | undefined;\n @property({type: Boolean}) atAngleSetpoint: boolean = false;\n @property({type: Number}) angleSetpointAtZeroDeadband: number = 0.5;\n @property({type: Boolean}) setpointOverride: boolean = false;\n @property({type: Boolean}) touching: boolean = false;\n\n @property({type: Boolean}) animateSetpoint: boolean = false;\n\n @state() private _departingNewAngleSetpoint: number | undefined;\n private _animationTimer?: ReturnType<typeof setTimeout>;\n\n /**\n * Accumulated CSS-safe angle for the original setpoint marker.\n * Ensures CSS rotate() transitions always take the shortest path,\n * even across the 0°/360° boundary.\n */\n private _setpointCssAngle: number = 0;\n\n /** Whether the setpoint CSS angle has been initialised (to skip transition on first render). */\n private _setpointCssAngleInit = false;\n @property({type: Number}) padding: number | undefined;\n @property({type: Array, attribute: false}) areas: WatchArea[] = [];\n @property({type: Array, attribute: false}) barAreas: WatchBarArea[] = [];\n @property({type: Array, attribute: false}) needles: WatchNeedle[] = [];\n @property({type: Array, attribute: false}) tickmarks: Tickmark[] = [];\n @property({type: Boolean}) tickmarksInside: boolean = false;\n @property({type: String}) tickmarkStyle: TickmarkStyle =\n TickmarkStyle.regular;\n @property({type: Array, attribute: false}) advices: AngleAdviceRaw[] = [];\n @property({type: Boolean}) crosshairEnabled: boolean = false;\n @property({type: Boolean}) showLabels: boolean = false;\n @property({type: Array, attribute: false}) vessels: WatchVessel[] = [];\n @property({type: Number}) wind: number | null = null;\n @property({type: Number}) windFromDirectionDeg: number | null = null;\n @property({type: Number}) windSymbolRadius: number | null = null;\n @property({type: String}) windColor: string | undefined;\n @property({type: Number}) current: number | null = null;\n @property({type: Number}) currentFromDirectionDeg: number | null = null;\n @property({type: Number}) currentSymbolRadius: number | null = null;\n @property({type: String}) currentColor: string | undefined;\n @property({type: Boolean}) starboardPortIndicator: boolean = false;\n @property({type: Number}) clipTop: number = 0; // in percent of height\n @property({type: Number}) clipBottom: number = 0; // in percent of height\n @property({type: Number}) scaleWindIcon: number = 1;\n @property({type: Number}) rotation: number | undefined;\n @property({type: Boolean}) zoomToFitArc: boolean = false;\n @property({attribute: false}) arcFrame: ZoomToFitArcFrame | undefined;\n @property({type: Number}) tickFadeAngle: number = 0;\n\n @property({type: String}) rotType: RotType | undefined;\n @property({type: String}) rotPosition: RotPosition = RotPosition.innerCircle;\n @property({type: Number}) rotStartAngle: number = 0;\n @property({type: Number}) rotEndAngle: number = 0;\n @property({type: String}) rotPriority: Priority | undefined;\n @property({type: Number})\n set rotationsPerMinute(value: number) {\n this._rotationsPerMinute = value;\n if (this._rotController) {\n this._rotController.rotationsPerMinute = value;\n }\n }\n get rotationsPerMinute() {\n return this._rotationsPerMinute;\n }\n private _rotationsPerMinute = 0;\n private _rotController?: RateOfTurnController;\n\n // @ts-expect-error TS6133: The controller ensures that the render\n // function is called on resize of the element\n private _resizeController = new ResizeController(this, {});\n\n override willUpdate(changed: PropertyValues): void {\n super.willUpdate(changed);\n\n // Detect confirm: newAngleSetpoint was defined, now undefined\n if (changed.has('newAngleSetpoint') && this.animateSetpoint) {\n const prev = changed.get('newAngleSetpoint') as number | undefined;\n if (prev !== undefined && this.newAngleSetpoint === undefined) {\n this._departingNewAngleSetpoint = prev;\n clearTimeout(this._animationTimer);\n const duration = getSetpointAnimationDurationMs(this);\n this._animationTimer = setTimeout(() => {\n this._departingNewAngleSetpoint = undefined;\n }, duration);\n }\n }\n }\n\n override disconnectedCallback(): void {\n super.disconnectedCallback();\n clearTimeout(this._animationTimer);\n this._rotController = disposeRotController(this, this._rotController);\n }\n\n override updated(changed: PropertyValues): void {\n super.updated(changed);\n const el = this.rotType\n ? this.renderRoot.querySelector('#rot-spinner')\n : null;\n if (!el) {\n this._rotController = disposeRotController(this, this._rotController);\n return;\n }\n if (!this._rotController || this._rotController.el !== el) {\n this._rotController = disposeRotController(this, this._rotController);\n this._rotController = new RateOfTurnController(\n this,\n el,\n this._rotationsPerMinute\n );\n }\n }\n\n private get innerRingRadius(): number {\n return innerRingRadiusFor(this.watchCircleType);\n }\n\n private _rOff = 0;\n\n private watchCircle(): SVGTemplateResult | SVGTemplateResult[] {\n const rings = [];\n if (this.state !== InstrumentState.off) {\n rings.push(svg`\n <circle\n cx=\"0\"\n cy=\"0\"\n r=\"${172 + this._rOff}\"\n stroke=\"var(--instrument-frame-primary-color)\"\n fill=\"none\"\n stroke-width=\"24\"\n />`);\n\n if (this.watchCircleType !== WatchCircleType.single) {\n const r1 = RING2_RADIUS + this._rOff;\n const r2 =\n (this.watchCircleType === WatchCircleType.doubleThin\n ? RING3B_RADIUS\n : RING3_RADIUS) + this._rOff;\n const r = (r1 + r2) / 2;\n const strokeWidth = r1 - r2;\n rings.push(\n svg`\n <circle cx=\"0\" cy=\"0\" r=${r} stroke=\"var(--instrument-frame-secondary-color)\" stroke-width=${strokeWidth} fill=\"none\" />\n <circle cx=\"0\" cy=\"0\" r=${r1} stroke=\"var(--instrument-frame-secondary-color)\" stroke-width=\"1\" fill=\"none\" vector-effect=\"non-scaling-stroke\" />\n <circle cx=\"0\" cy=\"0\" r=${r2} stroke=\"var(--instrument-frame-secondary-color)\" stroke-width=\"1\" fill=\"none\" vector-effect=\"non-scaling-stroke\" />\n `\n );\n }\n if (this.watchCircleType === WatchCircleType.triple) {\n const r1 = RING3_RADIUS + this._rOff;\n const r2 = RING4_RADIUS + this._rOff;\n const r = (r1 + r2) / 2;\n const strokeWidth = r1 - r2;\n rings.push(\n svg`<circle cx=\"0\" cy=\"0\" r=${r} stroke=\"var(--instrument-frame-primary-color)\" stroke-width=${strokeWidth} fill=\"none\" />`\n );\n }\n }\n\n const maskSize = Math.max(200, OUTER_RING_RADIUS + this._rOff + 50);\n let result = rings;\n if (this.areas.length > 0) {\n const areas = this.areas.map((area) => {\n const svgPath = roundedArch({\n startAngle: area.startAngle,\n endAngle: area.endAngle,\n R: OUTER_RING_RADIUS + this._rOff,\n r: this.innerRingRadius + this._rOff,\n roundOutsideCut: area.roundOutsideCut,\n roundInsideCut: area.roundInsideCut,\n });\n return svgPath;\n });\n const mask = svg`<mask id=\"cutMask\">\n <rect x=\"${-maskSize}\" y=\"${-maskSize}\" width=\"${maskSize * 2}\" height=\"${maskSize * 2}\" fill=\"black\" />\n ${areas.map((area) => svg`<path d=${area} fill=\"white\" vector-effect=\"non-scaling-stroke\" stroke=\"white\" stroke-width=\"1\"/>`)}\n </mask>`;\n // clipPath for ROT uses r=0 so dots at any track radius stay visible\n const rotClip = svg`<clipPath id=\"rot-arc-clip\">${this.areas.map(\n (area) =>\n svg`<path d=${roundedArch({\n startAngle: area.startAngle,\n endAngle: area.endAngle,\n R: OUTER_RING_RADIUS + this._rOff + 20,\n r: 0,\n roundOutsideCut: area.roundOutsideCut,\n roundInsideCut: area.roundInsideCut,\n })} />`\n )}</clipPath>`;\n result = [mask, rotClip, svg`<g mask=\"url(#cutMask)\">${rings}</g>`];\n areas.forEach((area) => {\n result.push(\n svg`<path d=${area} fill=\"none\" stroke=\"var(--instrument-frame-tertiary-color)\" vector-effect=\"non-scaling-stroke\"/>`\n );\n });\n } else {\n if (this.state !== InstrumentState.off) {\n result.push(\n circle('outerRing', {\n radius: OUTER_RING_RADIUS + this._rOff,\n strokeWidth: 1,\n strokeColor: 'var(--instrument-frame-tertiary-color)',\n strokePosition: 'center',\n fillColor: 'none',\n })\n );\n\n result.push(svg`\n ${circle('innerRing', {\n radius: this.innerRingRadius + this._rOff,\n strokeWidth: 1,\n strokeColor: 'var(--instrument-frame-tertiary-color)',\n strokePosition: 'center',\n fillColor: 'none',\n })}\n `);\n } else {\n result.push(svg`\n ${circle('innerRing', {\n radius: OUTER_RING_RADIUS + this._rOff,\n strokeWidth: 1,\n strokeColor: 'var(--instrument-frame-tertiary-color)',\n strokePosition: 'center',\n fillColor: 'none',\n })}\n `);\n }\n }\n return result;\n }\n\n private _renderTickFadeDefs(): SVGTemplateResult | typeof nothing {\n if (this.tickFadeAngle <= 0 || this.areas.length === 0) return nothing;\n const area = this.areas[0];\n const arcSpan = area.endAngle - area.startAngle;\n const fade = Math.min(this.tickFadeAngle, arcSpan / 4);\n if (fade < 0.5) return nothing;\n\n const {startAngle, endAngle} = area;\n const R = OUTER_RING_RADIUS + this._rOff + 200;\n const toRad = (deg: number) => (deg * Math.PI) / 180;\n const px = (deg: number) => R * Math.sin(toRad(deg));\n const py = (deg: number) => -R * Math.cos(toRad(deg));\n\n const pieSlice = (a: number, b: number): string => {\n const x1 = px(a),\n y1 = py(a);\n const x2 = px(b),\n y2 = py(b);\n const largeArc = b - a > 180 ? 1 : 0;\n return `M 0 0 L ${x1} ${y1} A ${R} ${R} 0 ${largeArc} 1 ${x2} ${y2} Z`;\n };\n\n const Rm = (OUTER_RING_RADIUS + this.innerRingRadius) / 2 + this._rOff;\n const gx = (deg: number) => Rm * Math.sin(toRad(deg));\n const gy = (deg: number) => -Rm * Math.cos(toRad(deg));\n\n return svg`\n <defs>\n <linearGradient id=\"tickFadeL\" gradientUnits=\"userSpaceOnUse\"\n x1=\"${gx(startAngle)}\" y1=\"${gy(startAngle)}\"\n x2=\"${gx(startAngle + fade)}\" y2=\"${gy(startAngle + fade)}\">\n <stop offset=\"0\" stop-color=\"black\" />\n <stop offset=\"1\" stop-color=\"white\" />\n </linearGradient>\n <linearGradient id=\"tickFadeR\" gradientUnits=\"userSpaceOnUse\"\n x1=\"${gx(endAngle - fade)}\" y1=\"${gy(endAngle - fade)}\"\n x2=\"${gx(endAngle)}\" y2=\"${gy(endAngle)}\">\n <stop offset=\"0\" stop-color=\"white\" />\n <stop offset=\"1\" stop-color=\"black\" />\n </linearGradient>\n <mask id=\"tickFadeMask\" maskUnits=\"userSpaceOnUse\"\n x=\"${-R}\" y=\"${-R}\" width=\"${R * 2}\" height=\"${R * 2}\">\n <path d=\"${pieSlice(startAngle + fade, endAngle - fade)}\" fill=\"white\" />\n <path d=\"${pieSlice(startAngle, startAngle + fade)}\" fill=\"url(#tickFadeL)\" />\n <path d=\"${pieSlice(endAngle - fade, endAngle)}\" fill=\"url(#tickFadeR)\" />\n </mask>\n </defs>\n `;\n }\n\n private renderCrosshair(\n radius: number,\n labelKnockouts?: {\n positions: LabelPosition[];\n rotation: number | undefined;\n scale: number;\n /** Inner ring radius – crosshair is hidden between labelRadius and this value. */\n innerRingRadius: number;\n }\n ): SVGTemplateResult {\n const hasMask = labelKnockouts && labelKnockouts.positions.length > 0;\n\n // Radius at which labels sit (distance from centre).\n // Any position is equally valid — they're all at the same radial distance.\n const labelRadius = hasMask\n ? Math.max(\n ...labelKnockouts!.positions.map((l) =>\n Math.abs(l.x !== 0 ? l.x : l.y)\n )\n )\n : 0;\n // Small extra padding so the crosshair doesn't start/end right at the\n // label edge — use the same visual pad as the letter knockouts.\n const ringGapPad = hasMask ? 3 / labelKnockouts!.scale : 0;\n\n return svg`\n ${\n hasMask\n ? svg`\n <defs>\n <mask\n id=\"crosshair-label-mask\"\n maskUnits=\"userSpaceOnUse\"\n x=\"-${radius}\" y=\"-${radius}\"\n width=\"${radius * 2}\" height=\"${radius * 2}\"\n >\n <rect x=\"-${radius}\" y=\"-${radius}\" width=\"${radius * 2}\" height=\"${radius * 2}\" fill=\"white\"/>\n <!-- Annular ring knockout: hide crosshair between labels and inner ring -->\n <circle cx=\"0\" cy=\"0\" r=\"${labelKnockouts!.innerRingRadius}\" fill=\"black\"/>\n <circle cx=\"0\" cy=\"0\" r=\"${labelRadius - ringGapPad}\" fill=\"white\"/>\n <!-- Per-label rectangular knockouts -->\n ${labelKnockouts!.positions.map((l) => {\n const fontSize = 12 / labelKnockouts!.scale;\n const pad = 3 / labelKnockouts!.scale;\n const size = fontSize + pad * 2;\n return svg`\n <rect\n x=\"${l.x - size / 2}\" y=\"${l.y - size / 2}\"\n width=\"${size}\" height=\"${size}\"\n fill=\"black\"\n transform=\"rotate(${-(labelKnockouts!.rotation ?? 0)})\"\n transform-origin=\"${l.x} ${l.y}\"\n />\n `;\n })}\n </mask>\n </defs>`\n : nothing\n }\n <g mask=${hasMask ? 'url(#crosshair-label-mask)' : nothing}>\n <line\n x1=\"-${radius}\"\n y1=\"0\"\n x2=\"${radius}\"\n y2=\"0\"\n stroke=\"var(--instrument-frame-tertiary-color)\"\n stroke-width=\"1\"\n vector-effect=\"non-scaling-stroke\"\n />\n <line\n x1=\"0\"\n y1=\"-${radius}\"\n x2=\"0\"\n y2=\"${radius}\"\n stroke=\"var(--instrument-frame-tertiary-color)\"\n stroke-width=\"1\"\n vector-effect=\"non-scaling-stroke\"\n />\n </g>\n `;\n }\n\n private renderBars(): SVGTemplateResult[] | typeof nothing {\n if (this.barAreas.length === 0) {\n return nothing;\n }\n return this.barAreas.map((bar, index) => {\n const startAngle = Math.min(bar.startAngle, bar.endAngle);\n const endAngle = Math.max(bar.startAngle, bar.endAngle);\n const arc = roundedArch({\n r: RING3_RADIUS + this._rOff,\n R: RING2_RADIUS + this._rOff,\n startAngle: startAngle,\n endAngle: endAngle,\n roundInsideCut: false,\n roundOutsideCut: false,\n });\n const barMaskR = RING2_RADIUS + this._rOff + 40;\n // The mask is a sector to cut out the stroke on the start and end of the bar\n const mask = svg`<mask id=\"barMask-${index}\">\n <rect x=\"${-barMaskR}\" y=\"${-barMaskR}\" width=\"${barMaskR * 2}\" height=\"${barMaskR * 2}\" fill=\"black\" />\n <path d=${roundedArch({\n r: 1,\n R: barMaskR,\n startAngle: startAngle,\n endAngle: endAngle,\n roundInsideCut: false,\n roundOutsideCut: false,\n })} fill=\"white\" />\n </mask>`;\n return svg`\n ${mask}\n <g mask=\"url(#cutMask)\">\n <path \n d=${arc} \n fill=${bar.fillColor} \n stroke=${bar.fillColor} \n stroke-width=\"1\" \n vector-effect=\"non-scaling-stroke\" \n mask=\"url(#barMask-${index})\" \n />\n </g>\n `;\n });\n }\n\n private renderNeedles(): SVGTemplateResult[] | typeof nothing {\n if (this.needles.length === 0) {\n return nothing;\n }\n return this.needles.map((needle) => {\n return svg`\n <rect \n transform=\"rotate(${needle.angle})\" \n x=\"-4\" y=\"${-(RING2_RADIUS + this._rOff)}\" width=\"8\" height=\"48\" rx=\"4\" \n fill=${needle.fillColor} \n stroke=${needle.strokeColor}\n stroke-width=\"1\"\n vector-effect=\"non-scaling-stroke\"\n paint-order=\"stroke fill\"\n />\n `;\n });\n }\n\n private getScale({width, height}: {width: number; height: number}): number {\n let clientWidth = this.clientWidth;\n let clientHeight = this.clientHeight;\n if (clientWidth === 0 || clientHeight === 0) {\n const box = this.parentElement?.getBoundingClientRect();\n if (box) {\n clientWidth = box.width;\n clientHeight = box.height;\n }\n }\n const scale = Math.min(clientWidth / width, clientHeight / height);\n if (scale === Infinity || scale < 0) {\n throw new Error('Watch scale is not valid');\n }\n return scale;\n }\n\n private getPadding(): number {\n if (this.padding !== undefined) {\n return this.padding;\n }\n const hasTickmarksWithText =\n this.tickmarks.length > 0 &&\n this.tickmarks.some((t) => t.text !== undefined);\n if (hasTickmarksWithText && !this.tickmarksInside) {\n return 24 * 2.5;\n }\n return 24;\n }\n\n override render() {\n let width: number;\n let height: number;\n let viewBox: string;\n\n if (this.arcFrame) {\n this._rOff = this.arcFrame.radiusOffset;\n width = this.arcFrame.width;\n height = this.arcFrame.height;\n viewBox = this.arcFrame.viewBox;\n } else if (this.zoomToFitArc && this.areas.length > 0) {\n const ext = this.getPadding();\n const targetSize = (176 + ext) * 2;\n const frame = computeZoomToFitArcFrame({\n areas: this.areas,\n outerRadius: OUTER_RING_RADIUS,\n innerRadius: this.innerRingRadius,\n extension: ext,\n targetSize,\n });\n this._rOff = frame.radiusOffset;\n width = frame.width;\n height = frame.height;\n viewBox = frame.viewBox;\n } else {\n this._rOff = 0;\n width = (176 + this.getPadding()) * 2;\n height = width * (1 - this.clipTop / 100 - this.clipBottom / 100);\n const top = -width / 2 + (width * this.clipTop) / 100;\n viewBox = `-${width / 2} ${top} ${width} ${height}`;\n }\n\n const rOff = this._rOff;\n const scale = this.getScale({width, height});\n const angleSetpoint = this.renderSetpoint();\n const textRadius =\n (this.tickmarksInside ? this.innerRingRadius : OUTER_RING_RADIUS) + rOff;\n const maxDigits = Math.max(\n ...this.tickmarks.map((t) => t.text?.length ?? 0)\n );\n const tickmarks = this.tickmarks.map((t) =>\n tickmark(t.angle, {\n size: t.type,\n style: this.tickmarkStyle,\n scale,\n text: this.showLabels ? undefined : t.text,\n inside: this.tickmarksInside,\n textRadius,\n rotation: this.rotation,\n maxDigits,\n color: t.color,\n radiusOffset: rOff,\n })\n );\n const advices = this.advices\n ? this.advices.map((a) => renderAdvice(a, rOff))\n : nothing;\n\n // Compute label positions once – used for both rendering and crosshair knockout.\n const insideLabels = this.tickmarksInside && this.showLabels;\n const includeNorth = !this.northArrow;\n const labelPositions = this.showLabels\n ? getLabelPositions({\n scale,\n inside: this.tickmarksInside,\n innerRadius: this.innerRingRadius + rOff,\n includeNorth,\n })\n : undefined;\n\n const labels = labelPositions\n ? renderLabels({\n scale,\n rotation: this.rotation,\n inside: this.tickmarksInside,\n innerRadius: this.innerRingRadius + rOff,\n includeNorth,\n })\n : nothing;\n const northArrowEl = this.northArrow\n ? renderNorthArrow({\n scale,\n rotation: this.rotation,\n inside: this.northArrowInside ?? this.tickmarksInside,\n })\n : nothing;\n const wind =\n this.wind != null && this.windFromDirectionDeg != null\n ? svg`<g transform=\"scale(${this.scaleWindIcon})\">${renderWind({\n wind: this.wind,\n fromDirectionDeg: this.windFromDirectionDeg,\n radius: this.windSymbolRadius ?? 192,\n color: this.windColor,\n })}</g>`\n : nothing;\n const current =\n this.current != null && this.currentFromDirectionDeg != null\n ? renderCurrent({\n current: this.current,\n fromDirectionDeg: this.currentFromDirectionDeg,\n radius: this.currentSymbolRadius ?? 192,\n color: this.currentColor,\n })\n : nothing;\n return html`\n <svg\n width=\"100%\"\n height=\"100%\"\n viewBox=${viewBox}\n style=\"--scale: ${scale}\"\n transform=\"rotate(${this.rotation ?? 0})\"\n >\n ${this.watchCircle()} ${this.renderBars()}\n ${this.crosshairEnabled\n ? this.renderCrosshair(\n OUTER_RING_RADIUS + rOff,\n insideLabels && labelPositions\n ? {\n positions: labelPositions,\n rotation: this.rotation,\n scale,\n innerRingRadius: this.innerRingRadius + rOff,\n }\n : undefined\n )\n : nothing}\n ${northArrowEl} ${this.renderStarboardPortIndicator()} ${current}\n ${this._renderTickFadeDefs()} ${wind}\n ${this.tickFadeAngle > 0 && this.areas.length > 0\n ? svg`<g mask=\"url(#tickFadeMask)\">${tickmarks}</g>`\n : tickmarks}\n ${this.areas.length > 0\n ? svg`<g clip-path=\"url(#rot-arc-clip)\">${this.renderRot()}</g>`\n : this.renderRot()}\n ${advices} ${angleSetpoint}\n ${this.tickFadeAngle > 0 && this.areas.length > 0\n ? svg`<g mask=\"url(#tickFadeMask)\">${labels}</g>`\n : labels}\n ${this.renderVesselImage()} ${this.renderNeedles()}\n </svg>\n `;\n }\n\n private getRotColors(): {\n dotColor: string;\n barBgColor: string;\n endDotFill: string;\n endDotStroke: string;\n } {\n const p = this.rotPriority ?? this.priority;\n const isEnhanced = p === Priority.enhanced;\n const isInner = this.rotPosition === RotPosition.innerCircle;\n\n if (isInner) {\n return {\n dotColor: isEnhanced\n ? 'var(--instrument-enhanced-tertiary-color)'\n : 'var(--instrument-regular-tertiary-color)',\n barBgColor: isEnhanced\n ? 'var(--instrument-enhanced-secondary-color)'\n : 'var(--instrument-regular-secondary-color)',\n endDotFill: 'var(--border-silhouette-color)',\n endDotStroke: isEnhanced\n ? 'var(--instrument-enhanced-secondary-color)'\n : 'var(--instrument-regular-secondary-color)',\n };\n }\n\n return {\n dotColor: isEnhanced\n ? 'var(--instrument-enhanced-secondary-color)'\n : 'var(--instrument-regular-secondary-color)',\n barBgColor: isEnhanced\n ? 'var(--instrument-enhanced-tertiary-color)'\n : 'var(--instrument-regular-tertiary-color)',\n endDotFill: isEnhanced\n ? 'var(--instrument-enhanced-secondary-color)'\n : 'var(--border-silhouette-color)',\n endDotStroke: isEnhanced\n ? 'var(--instrument-frame-primary-color)'\n : 'var(--instrument-regular-secondary-color)',\n };\n }\n\n private renderRot(): SVGTemplateResult | typeof nothing {\n if (!this.rotType) return nothing;\n\n const {dotColor, barBgColor, endDotFill, endDotStroke} =\n this.getRotColors();\n const rOff = this._rOff;\n\n if (this.rotType === RotType.bar) {\n const hasBar =\n shortestAngularDeltaDeg(this.rotStartAngle, this.rotEndAngle) >= 0.1;\n return svg`\n ${renderRotBarStatic({\n startAngle: this.rotStartAngle,\n endAngle: this.rotEndAngle,\n color: dotColor,\n barColor: barBgColor,\n position: this.rotPosition,\n endDotFill,\n endDotStroke,\n maskId: 'rot-bar-mask',\n radiusOffset: rOff,\n })}\n ${\n hasBar\n ? svg`<g clip-path=\"url(#rot-bar-mask)\">\n <g id=\"rot-spinner\">\n ${renderRotBarDots(dotColor, this.rotPosition, rOff)}\n </g>\n </g>`\n : nothing\n }\n `;\n }\n\n const p = this.rotPriority ?? this.priority;\n const dotsColor =\n p === Priority.enhanced\n ? 'var(--instrument-enhanced-secondary-color)'\n : 'var(--instrument-regular-secondary-color)';\n return svg`\n <g id=\"rot-spinner\">\n ${renderRotDots(dotsColor, this.rotPosition, rOff)}\n </g>\n `;\n }\n\n private renderSetpoint(): SVGTemplateResult | typeof nothing {\n if (this.angleSetpoint === undefined) {\n return nothing;\n }\n\n const derived = deriveRadialSetpointConfig({\n state: this.state,\n priority: this.priority,\n atSetpoint: this.atAngleSetpoint,\n angleSetpoint: this.angleSetpoint,\n setpointAtZeroDeadband: this.angleSetpointAtZeroDeadband,\n newAngleSetpoint: this.newAngleSetpoint,\n touching: this.touching,\n setpointOverride: this.setpointOverride,\n });\n\n const {visualState, colorMode, disabled, hasNewSetpoint} = derived;\n\n const outwardOffset = getSetpointOutwardOffset(visualState);\n const radius =\n RADIAL_SETPOINT_RADIUS +\n this._rOff +\n outwardOffset -\n RADIAL_SETPOINT_INWARD_ADJUST;\n\n // Render original setpoint marker (dimmed when newAngleSetpoint is active)\n const opacity = hasNewSetpoint ? 0.75 : 1;\n const originalMarker = drawSetpointMarker({\n visualState,\n colorMode,\n disabled,\n id: this._setpointId,\n });\n\n const animate = this.animateSetpoint;\n const hasDeparting = this._departingNewAngleSetpoint !== undefined;\n\n // Compute CSS-safe accumulated angle so transitions always take the short path\n const rawAngle = this.angleSetpoint + 90;\n if (!this._setpointCssAngleInit) {\n // First render: set angle without transition\n this._setpointCssAngle = rawAngle;\n this._setpointCssAngleInit = true;\n } else {\n this._setpointCssAngle = cssSafeAngle(this._setpointCssAngle, rawAngle);\n }\n\n // Use CSS style transform when animating for smooth transition\n const originalSetpoint = animate\n ? svg`\n <g style=\"transform: rotate(${this._setpointCssAngle}deg) translateX(${-radius}px) rotate(270deg); opacity: ${opacity}; transition: transform var(${SETPOINT_ANIMATION_CSS_VAR}, ${SETPOINT_ANIMATION_DURATION_DEFAULT}) ease-out, opacity var(${SETPOINT_ANIMATION_CSS_VAR}, ${SETPOINT_ANIMATION_DURATION_DEFAULT}) ease-out;\">\n ${originalMarker}\n </g>\n `\n : svg`\n <g transform=\"rotate(${this.angleSetpoint + 90}) translate(${-radius}, 0) rotate(270)\" opacity=\"${opacity}\">\n ${originalMarker}\n </g>\n `;\n\n // Render newAngleSetpoint in focus state (always on top)\n // OR render departing newAngleSetpoint during confirm fade-out\n if (hasNewSetpoint || hasDeparting) {\n const isActive = hasNewSetpoint;\n const newAngle = isActive\n ? this.newAngleSetpoint!\n : this._departingNewAngleSetpoint!;\n const targetOpacity = isActive ? 1 : 0;\n\n const focusOutwardOffset = getSetpointOutwardOffset(\n SetpointVisualState.focus\n );\n const focusRadius =\n RADIAL_SETPOINT_RADIUS +\n this._rOff +\n focusOutwardOffset -\n RADIAL_SETPOINT_INWARD_ADJUST;\n\n const newMarker = drawSetpointMarker({\n visualState: SetpointVisualState.focus,\n colorMode,\n disabled: false, // newSetpoint is never disabled\n id: this._newSetpointId,\n });\n\n if (animate) {\n const duration = `var(${SETPOINT_ANIMATION_CSS_VAR}, ${SETPOINT_ANIMATION_DURATION_DEFAULT})`;\n return svg`\n ${originalSetpoint}\n <g style=\"transform: rotate(${newAngle + 90}deg) translateX(${-focusRadius}px) rotate(270deg); opacity: ${targetOpacity}; transition: opacity ${duration} ease-out;\">\n ${newMarker}\n </g>\n `;\n }\n\n return svg`\n ${originalSetpoint}\n <g transform=\"rotate(${newAngle + 90}) translate(${-focusRadius}, 0) rotate(270)\" opacity=\"${targetOpacity}\">\n ${newMarker}\n </g>\n `;\n }\n\n return originalSetpoint;\n }\n\n private renderVesselImage(): SVGTemplateResult[] | typeof nothing {\n if (this.vessels.length === 0) {\n return nothing;\n }\n\n return this.vessels.map((v) => {\n let size;\n switch (v.size) {\n case VesselImageSize.large:\n size = 224;\n break;\n case VesselImageSize.medium:\n size = 160;\n break;\n default:\n size = 100;\n }\n\n const scale = size / 160;\n return svg`<g style=\"transform: ${v.transform} scale(${scale}) translate(-80px, -80px) \">${vesselImages[v.vesselImage]}</g>`;\n });\n }\n\n private renderStarboardPortIndicator(): SVGTemplateResult[] | typeof nothing {\n if (!this.starboardPortIndicator) {\n return nothing;\n }\n return [\n adviceMask(\n 0,\n 180,\n 'var(--instrument-starboard-secondary-color)',\n 'var(--instrument-starboard-secondary-color)'\n ),\n adviceMask(\n 180,\n 360,\n 'var(--instrument-port-secondary-color)',\n 'var(--instrument-port-secondary-color)'\n ),\n ] as SVGTemplateResult[];\n }\n\n static override styles = unsafeCSS(compentStyle);\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'obc-watch': ObcWatch;\n }\n}\n"],"names":["WatchCircleType"],"mappings":"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"}
|
|
@@ -1,6 +1,9 @@
|
|
|
1
|
-
import { LitElement, SVGTemplateResult } from 'lit';
|
|
1
|
+
import { LitElement, PropertyValues, SVGTemplateResult } from 'lit';
|
|
2
2
|
import { Tickmark } from './tickmark-flat.js';
|
|
3
3
|
import { Label } from '../compass-flat/compass-flat.js';
|
|
4
|
+
import { Priority } from '../types.js';
|
|
5
|
+
import { RotType, LinearRotPosition } from '../rate-of-turn/rot-renderer.js';
|
|
6
|
+
export { RotType, LinearRotPosition };
|
|
4
7
|
export declare class ObcWatchFlat extends LitElement {
|
|
5
8
|
width: number;
|
|
6
9
|
height: number;
|
|
@@ -14,10 +17,35 @@ export declare class ObcWatchFlat extends LitElement {
|
|
|
14
17
|
trackHeight: number;
|
|
15
18
|
ticksHeight: number;
|
|
16
19
|
borderRadius: number;
|
|
20
|
+
bottomBar: boolean;
|
|
21
|
+
rotType: RotType | undefined;
|
|
22
|
+
rotPosition: LinearRotPosition;
|
|
23
|
+
/** Bar start position in SVG user-space x-coordinates (center-origin). Computed by the parent instrument. */
|
|
24
|
+
rotStartX: number;
|
|
25
|
+
/** Bar end position in SVG user-space x-coordinates (center-origin). Computed by the parent instrument. */
|
|
26
|
+
rotEndX: number;
|
|
27
|
+
/**
|
|
28
|
+
* Pixel spacing between adjacent dots in the linear ROT strip.
|
|
29
|
+
* Must be > 0 to enable animation; the default `0` intentionally disables
|
|
30
|
+
* the spinning dots so the parent instrument must supply a meaningful value
|
|
31
|
+
* derived from the current scale (e.g. `LINEAR_DOT_ANGLE_SPACING * translationScale`).
|
|
32
|
+
*/
|
|
33
|
+
rotDotSpacing: number;
|
|
34
|
+
rotPriority: Priority;
|
|
35
|
+
set rotationsPerMinute(value: number);
|
|
36
|
+
get rotationsPerMinute(): number;
|
|
37
|
+
private _rotationsPerMinute;
|
|
38
|
+
private _rotController?;
|
|
39
|
+
private get totalHeight();
|
|
17
40
|
private renderClipPath;
|
|
18
41
|
private renderLabelMask;
|
|
19
42
|
private renderLabels;
|
|
20
43
|
private watchFace;
|
|
44
|
+
private getRotTrackY;
|
|
45
|
+
private getRotColors;
|
|
46
|
+
private renderRot;
|
|
47
|
+
updated(changed: PropertyValues): void;
|
|
48
|
+
disconnectedCallback(): void;
|
|
21
49
|
render(): import('lit-html').TemplateResult<1>;
|
|
22
50
|
static styles: import('lit').CSSResult;
|
|
23
51
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"watch-flat.d.ts","sourceRoot":"","sources":["../../../src/navigation-instruments/watch-flat/watch-flat.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"watch-flat.d.ts","sourceRoot":"","sources":["../../../src/navigation-instruments/watch-flat/watch-flat.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,UAAU,EACV,cAAc,EACd,iBAAiB,EAKlB,MAAM,KAAK,CAAC;AAGb,OAAO,EAAC,QAAQ,EAA0B,MAAM,oBAAoB,CAAC;AAErE,OAAO,EAAC,KAAK,EAAC,MAAM,iCAAiC,CAAC;AAEtD,OAAO,EAAC,QAAQ,EAAC,MAAM,aAAa,CAAC;AACrC,OAAO,EACL,OAAO,EACP,iBAAiB,EAKlB,MAAM,iCAAiC,CAAC;AAMzC,OAAO,EAAC,OAAO,EAAE,iBAAiB,EAAC,CAAC;AAEpC,qBACa,YAAa,SAAQ,UAAU;IAChB,KAAK,SAAO;IACZ,MAAM,SAAM;IACZ,OAAO,SAAK;IACZ,QAAQ,SAAK;IACb,eAAe,SAAK;IACpB,aAAa,EAAE,MAAM,GAAG,SAAS,CAAC;IACjB,SAAS,EAAE,QAAQ,EAAE,CAAM;IAC3B,MAAM,EAAE,KAAK,EAAE,CAAM;IACrB,YAAY,EAAE,iBAAiB,EAAE,CACvE;IACqB,WAAW,SAAyB;IACpC,WAAW,SAAkC;IAC7C,YAAY,SAAK;IAChB,SAAS,UAAS;IAEnB,OAAO,EAAE,OAAO,GAAG,SAAS,CAAC;IAC7B,WAAW,EAAE,iBAAiB,CAC9B;IAC1B,6GAA6G;IACnF,SAAS,EAAE,MAAM,CAAK;IAChD,2GAA2G;IACjF,OAAO,EAAE,MAAM,CAAK;IAC9C;;;;;OAKG;IACuB,aAAa,EAAE,MAAM,CAAK;IAC1B,WAAW,EAAE,QAAQ,CAAoB;IAEnE,IACI,kBAAkB,CAAC,KAAK,EAAE,MAAM,EAKnC;IACD,IAAI,kBAAkB,IANQ,MAAM,CAQnC;IAED,OAAO,CAAC,mBAAmB,CAAK;IAChC,OAAO,CAAC,cAAc,CAAC,CAAuB;IAE9C,OAAO,KAAK,WAAW,GAEtB;IAED,OAAO,CAAC,cAAc;IAUtB,OAAO,CAAC,eAAe;IAqBvB,OAAO,CAAC,YAAY;IAgBpB,OAAO,CAAC,SAAS;IA6DjB,OAAO,CAAC,YAAY;IAWpB,OAAO,CAAC,YAAY;IAqBpB,OAAO,CAAC,SAAS;IA8CR,OAAO,CAAC,OAAO,EAAE,cAAc,GAAG,IAAI;IA0BtC,oBAAoB,IAAI,IAAI;IAK5B,MAAM;IAsCf,OAAgB,MAAM,0BAA2B;CAClD;AAED,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,gBAAgB,EAAE,YAAY,CAAC;KAChC;CACF"}
|
|
@@ -1,9 +1,12 @@
|
|
|
1
|
-
import { unsafeCSS, LitElement, svg, html } from "lit";
|
|
1
|
+
import { unsafeCSS, LitElement, svg, nothing, html } from "lit";
|
|
2
2
|
import { property } from "lit/decorators.js";
|
|
3
3
|
import compentStyle from "./watch-flat.css.js";
|
|
4
4
|
import { tickmark, TickmarkStyle } from "./tickmark-flat.js";
|
|
5
5
|
import { rect } from "../../svghelpers/rectangular.js";
|
|
6
6
|
import { customElement } from "../../decorator.js";
|
|
7
|
+
import { Priority } from "../types.js";
|
|
8
|
+
import { LinearRotPosition, RotType, renderLinearRotBarStatic, renderLinearRotBarDots, renderLinearRotDots, LINEAR_DOT_ANGLE_SPACING } from "../rate-of-turn/rot-renderer.js";
|
|
9
|
+
import { disposeRotController, RateOfTurnController } from "../rate-of-turn/rate-of-turn.controller.js";
|
|
7
10
|
var __defProp = Object.defineProperty;
|
|
8
11
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
9
12
|
var __decorateClass = (decorators, target, key, kind) => {
|
|
@@ -28,12 +31,31 @@ let ObcWatchFlat = class extends LitElement {
|
|
|
28
31
|
this.trackHeight = 2 / 3 * this.height;
|
|
29
32
|
this.ticksHeight = this.height - this.trackHeight;
|
|
30
33
|
this.borderRadius = 8;
|
|
34
|
+
this.bottomBar = false;
|
|
35
|
+
this.rotPosition = LinearRotPosition.track;
|
|
36
|
+
this.rotStartX = 0;
|
|
37
|
+
this.rotEndX = 0;
|
|
38
|
+
this.rotDotSpacing = 0;
|
|
39
|
+
this.rotPriority = Priority.regular;
|
|
40
|
+
this._rotationsPerMinute = 0;
|
|
41
|
+
}
|
|
42
|
+
set rotationsPerMinute(value) {
|
|
43
|
+
this._rotationsPerMinute = value;
|
|
44
|
+
if (this._rotController) {
|
|
45
|
+
this._rotController.rotationsPerMinute = value;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
get rotationsPerMinute() {
|
|
49
|
+
return this._rotationsPerMinute;
|
|
50
|
+
}
|
|
51
|
+
get totalHeight() {
|
|
52
|
+
return this.bottomBar ? this.height + this.ticksHeight : this.height;
|
|
31
53
|
}
|
|
32
54
|
renderClipPath(offsetY = 0) {
|
|
33
55
|
return svg`
|
|
34
56
|
<clipPath id="frameClipPath${offsetY === 0 ? "" : "Tickmarks"}">
|
|
35
|
-
<rect x="${-this.width / 2}" y="${-this.
|
|
36
|
-
width="${this.width}" height="${this.
|
|
57
|
+
<rect x="${-this.width / 2}" y="${-this.totalHeight / 2 + offsetY}"
|
|
58
|
+
width="${this.width}" height="${this.totalHeight}"
|
|
37
59
|
rx="${this.borderRadius}" />
|
|
38
60
|
</clipPath>
|
|
39
61
|
`;
|
|
@@ -73,6 +95,8 @@ let ObcWatchFlat = class extends LitElement {
|
|
|
73
95
|
}
|
|
74
96
|
watchFace() {
|
|
75
97
|
const strokeWidth = 1;
|
|
98
|
+
const th = this.totalHeight;
|
|
99
|
+
const topTicksY = -th / 2;
|
|
76
100
|
return svg`
|
|
77
101
|
${this.renderClipPath()}
|
|
78
102
|
${this.renderClipPath(-40)}
|
|
@@ -80,7 +104,7 @@ let ObcWatchFlat = class extends LitElement {
|
|
|
80
104
|
${rect("frame-track", {
|
|
81
105
|
width: this.width,
|
|
82
106
|
height: this.trackHeight,
|
|
83
|
-
y:
|
|
107
|
+
y: th / 2 - this.trackHeight - (this.bottomBar ? this.ticksHeight : 0),
|
|
84
108
|
strokeWidth,
|
|
85
109
|
strokeColor: "var(--instrument-frame-secondary-color)",
|
|
86
110
|
strokePosition: "inside",
|
|
@@ -90,17 +114,27 @@ let ObcWatchFlat = class extends LitElement {
|
|
|
90
114
|
${rect("frame-ticks", {
|
|
91
115
|
width: this.width,
|
|
92
116
|
height: this.ticksHeight,
|
|
93
|
-
y:
|
|
117
|
+
y: topTicksY,
|
|
94
118
|
strokeWidth,
|
|
95
119
|
strokeColor: "var(--instrument-frame-primary-color)",
|
|
96
120
|
strokePosition: "inside",
|
|
97
121
|
fillColor: "var(--instrument-frame-primary-color)",
|
|
98
122
|
borderRadius: 0
|
|
99
123
|
})}
|
|
124
|
+
${this.bottomBar ? rect("frame-bottom-bar", {
|
|
125
|
+
width: this.width,
|
|
126
|
+
height: this.ticksHeight,
|
|
127
|
+
y: th / 2 - this.ticksHeight,
|
|
128
|
+
strokeWidth,
|
|
129
|
+
strokeColor: "var(--instrument-frame-primary-color)",
|
|
130
|
+
strokePosition: "inside",
|
|
131
|
+
fillColor: "var(--instrument-frame-primary-color)",
|
|
132
|
+
borderRadius: 0
|
|
133
|
+
}) : nothing}
|
|
100
134
|
</g>
|
|
101
135
|
${rect("frame-outline", {
|
|
102
136
|
width: this.width,
|
|
103
|
-
height:
|
|
137
|
+
height: th,
|
|
104
138
|
strokeWidth,
|
|
105
139
|
strokeColor: "var(--instrument-frame-tertiary-color)",
|
|
106
140
|
strokePosition: "inside",
|
|
@@ -109,10 +143,90 @@ let ObcWatchFlat = class extends LitElement {
|
|
|
109
143
|
})}
|
|
110
144
|
`;
|
|
111
145
|
}
|
|
146
|
+
// ---------------------------------------------------------------------------
|
|
147
|
+
// ROT (Rate of Turn) — linear
|
|
148
|
+
// ---------------------------------------------------------------------------
|
|
149
|
+
getRotTrackY() {
|
|
150
|
+
const th = this.totalHeight;
|
|
151
|
+
if (this.rotPosition === LinearRotPosition.scale) {
|
|
152
|
+
return -th / 2 + this.ticksHeight / 2;
|
|
153
|
+
}
|
|
154
|
+
if (this.bottomBar) {
|
|
155
|
+
return th / 2 - this.ticksHeight / 2;
|
|
156
|
+
}
|
|
157
|
+
return this.height / 2 - this.trackHeight / 2;
|
|
158
|
+
}
|
|
159
|
+
getRotColors() {
|
|
160
|
+
const isEnhanced = this.rotPriority === Priority.enhanced;
|
|
161
|
+
return {
|
|
162
|
+
dotColor: isEnhanced ? "var(--instrument-enhanced-tertiary-color)" : "var(--instrument-regular-tertiary-color)",
|
|
163
|
+
barBgColor: isEnhanced ? "var(--instrument-enhanced-secondary-color)" : "var(--instrument-regular-secondary-color)",
|
|
164
|
+
endDotFill: "var(--border-silhouette-color)",
|
|
165
|
+
endDotStroke: isEnhanced ? "var(--instrument-enhanced-secondary-color)" : "var(--instrument-regular-secondary-color)"
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
renderRot() {
|
|
169
|
+
if (!this.rotType) return nothing;
|
|
170
|
+
const trackY = this.getRotTrackY();
|
|
171
|
+
const { dotColor, barBgColor, endDotFill, endDotStroke } = this.getRotColors();
|
|
172
|
+
const canAnimateDots = this.rotDotSpacing > 0;
|
|
173
|
+
if (this.rotType === RotType.bar) {
|
|
174
|
+
const hasBar = Math.abs(this.rotEndX - this.rotStartX) >= 1;
|
|
175
|
+
return svg`
|
|
176
|
+
${renderLinearRotBarStatic({
|
|
177
|
+
startX: this.rotStartX,
|
|
178
|
+
endX: this.rotEndX,
|
|
179
|
+
color: dotColor,
|
|
180
|
+
barColor: barBgColor,
|
|
181
|
+
trackY,
|
|
182
|
+
endDotFill,
|
|
183
|
+
endDotStroke,
|
|
184
|
+
maskId: "rot-bar-mask-linear"
|
|
185
|
+
})}
|
|
186
|
+
${hasBar && canAnimateDots ? svg`<g clip-path="url(#rot-bar-mask-linear)">
|
|
187
|
+
<g id="rot-spinner">
|
|
188
|
+
${renderLinearRotBarDots(dotColor, trackY, this.rotDotSpacing, this.width)}
|
|
189
|
+
</g>
|
|
190
|
+
</g>` : nothing}
|
|
191
|
+
`;
|
|
192
|
+
}
|
|
193
|
+
const dotsColor = this.rotPriority === Priority.enhanced ? "var(--instrument-enhanced-secondary-color)" : "var(--instrument-regular-secondary-color)";
|
|
194
|
+
return canAnimateDots ? svg`
|
|
195
|
+
<g id="rot-spinner">
|
|
196
|
+
${renderLinearRotDots(dotsColor, trackY, this.rotDotSpacing, this.width)}
|
|
197
|
+
</g>
|
|
198
|
+
` : nothing;
|
|
199
|
+
}
|
|
200
|
+
updated(changed) {
|
|
201
|
+
super.updated(changed);
|
|
202
|
+
const el = this.rotType ? this.renderRoot.querySelector("#rot-spinner") : null;
|
|
203
|
+
if (!el) {
|
|
204
|
+
this._rotController = disposeRotController(this, this._rotController);
|
|
205
|
+
return;
|
|
206
|
+
}
|
|
207
|
+
const cyclePx = 360 * (this.rotDotSpacing / LINEAR_DOT_ANGLE_SPACING);
|
|
208
|
+
if (!this._rotController || this._rotController.el !== el) {
|
|
209
|
+
this._rotController = disposeRotController(this, this._rotController);
|
|
210
|
+
this._rotController = new RateOfTurnController(
|
|
211
|
+
this,
|
|
212
|
+
el,
|
|
213
|
+
this._rotationsPerMinute,
|
|
214
|
+
cyclePx
|
|
215
|
+
);
|
|
216
|
+
} else {
|
|
217
|
+
this._rotController.cyclePx = cyclePx;
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
disconnectedCallback() {
|
|
221
|
+
super.disconnectedCallback();
|
|
222
|
+
this._rotController = disposeRotController(this, this._rotController);
|
|
223
|
+
}
|
|
112
224
|
render() {
|
|
113
225
|
const width = (this.width / 2 + this.padding) * 2;
|
|
114
|
-
const
|
|
226
|
+
const th = this.totalHeight;
|
|
227
|
+
const viewBox = `-${width / 2} -${th / 2} ${width} ${th}`;
|
|
115
228
|
const scale = this.clientWidth / width;
|
|
229
|
+
const contentOffsetY = this.bottomBar ? -this.ticksHeight / 2 : 0;
|
|
116
230
|
return html`
|
|
117
231
|
<svg
|
|
118
232
|
width="100%"
|
|
@@ -120,20 +234,25 @@ let ObcWatchFlat = class extends LitElement {
|
|
|
120
234
|
viewBox=${viewBox}
|
|
121
235
|
style="--scale: ${scale}"
|
|
122
236
|
>
|
|
123
|
-
${this.watchFace()} ${this.renderLabelMask()}
|
|
237
|
+
${this.watchFace()} ${this.renderLabelMask()}
|
|
124
238
|
|
|
125
|
-
<g
|
|
126
|
-
|
|
239
|
+
<g transform="translate(0, ${contentOffsetY})">
|
|
240
|
+
<g clip-path="url(#frameClipPath)">
|
|
241
|
+
${this.tickmarks.map(
|
|
127
242
|
(t) => svg`
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
243
|
+
<g transform="translate(${-this.rotation * this.tickmarkSpacing}, 0)">
|
|
244
|
+
${tickmark(t.angle, t.type, TickmarkStyle.regular)}
|
|
245
|
+
</g>
|
|
246
|
+
`
|
|
132
247
|
)}
|
|
248
|
+
</g>
|
|
249
|
+
|
|
250
|
+
<g mask="url(#labelMask)">${this.renderLabels(scale)}</g>
|
|
133
251
|
</g>
|
|
134
252
|
|
|
135
|
-
|
|
136
|
-
|
|
253
|
+
${this.FOVIndicator}
|
|
254
|
+
|
|
255
|
+
<g clip-path="url(#frameClipPath)">${this.renderRot()}</g>
|
|
137
256
|
</svg>
|
|
138
257
|
`;
|
|
139
258
|
}
|
|
@@ -175,10 +294,36 @@ __decorateClass([
|
|
|
175
294
|
__decorateClass([
|
|
176
295
|
property({ type: Number })
|
|
177
296
|
], ObcWatchFlat.prototype, "borderRadius", 2);
|
|
297
|
+
__decorateClass([
|
|
298
|
+
property({ type: Boolean })
|
|
299
|
+
], ObcWatchFlat.prototype, "bottomBar", 2);
|
|
300
|
+
__decorateClass([
|
|
301
|
+
property({ type: String })
|
|
302
|
+
], ObcWatchFlat.prototype, "rotType", 2);
|
|
303
|
+
__decorateClass([
|
|
304
|
+
property({ type: String })
|
|
305
|
+
], ObcWatchFlat.prototype, "rotPosition", 2);
|
|
306
|
+
__decorateClass([
|
|
307
|
+
property({ type: Number })
|
|
308
|
+
], ObcWatchFlat.prototype, "rotStartX", 2);
|
|
309
|
+
__decorateClass([
|
|
310
|
+
property({ type: Number })
|
|
311
|
+
], ObcWatchFlat.prototype, "rotEndX", 2);
|
|
312
|
+
__decorateClass([
|
|
313
|
+
property({ type: Number })
|
|
314
|
+
], ObcWatchFlat.prototype, "rotDotSpacing", 2);
|
|
315
|
+
__decorateClass([
|
|
316
|
+
property({ type: String })
|
|
317
|
+
], ObcWatchFlat.prototype, "rotPriority", 2);
|
|
318
|
+
__decorateClass([
|
|
319
|
+
property({ type: Number })
|
|
320
|
+
], ObcWatchFlat.prototype, "rotationsPerMinute", 1);
|
|
178
321
|
ObcWatchFlat = __decorateClass([
|
|
179
322
|
customElement("obc-watch-flat")
|
|
180
323
|
], ObcWatchFlat);
|
|
181
324
|
export {
|
|
182
|
-
|
|
325
|
+
LinearRotPosition,
|
|
326
|
+
ObcWatchFlat,
|
|
327
|
+
RotType
|
|
183
328
|
};
|
|
184
329
|
//# sourceMappingURL=watch-flat.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"watch-flat.js","sources":["../../../src/navigation-instruments/watch-flat/watch-flat.ts"],"sourcesContent":["import {LitElement, SVGTemplateResult, html, svg, unsafeCSS} from 'lit';\nimport {property} from 'lit/decorators.js';\nimport compentStyle from './watch-flat.css?inline';\nimport {Tickmark, TickmarkStyle, tickmark} from './tickmark-flat.js';\nimport {rect} from '../../svghelpers/rectangular.js';\nimport {Label} from '../compass-flat/compass-flat.js';\nimport {customElement} from '../../decorator.js';\n\n@customElement('obc-watch-flat')\nexport class ObcWatchFlat extends LitElement {\n @property({type: Number}) width = 352;\n @property({type: Number}) height = 72;\n @property({type: Number}) padding = 0;\n @property({type: Number}) rotation = 0;\n @property({type: Number}) tickmarkSpacing = 0;\n @property({type: Number}) angleSetpoint: number | undefined;\n @property({type: Array, attribute: false}) tickmarks: Tickmark[] = [];\n @property({type: Array, attribute: false}) labels: Label[] = [];\n @property({type: Array, attribute: false}) FOVIndicator: SVGTemplateResult[] =\n [];\n @property({type: Number}) trackHeight = (2 / 3) * this.height;\n @property({type: Number}) ticksHeight = this.height - this.trackHeight;\n @property({type: Number}) borderRadius = 8;\n\n private renderClipPath(offsetY: number = 0): SVGTemplateResult {\n return svg`\n <clipPath id=\"frameClipPath${offsetY === 0 ? '' : 'Tickmarks'}\">\n <rect x=\"${-this.width / 2}\" y=\"${-this.height / 2 + offsetY}\" \n width=\"${this.width}\" height=\"${this.height}\" \n rx=\"${this.borderRadius}\" />\n </clipPath>\n `;\n }\n\n private renderLabelMask(): SVGTemplateResult {\n return svg`\n <mask id=\"labelMask\">\n <rect x=\"${-this.width / 2}\" y=\"${-70}\" \n width=\"${this.width}\" height=\"${32}\"\n />\n <linearGradient id=\"fadeGradient\" gradientUnits=\"userSpaceOnUse\"\n x1=\"${-this.width / 2}\" y1=\"0\" x2=\"${this.width / 2}\" y2=\"0\">\n <stop offset=\"0%\" style=\"stop-color:black; stop-opacity:1;\" />\n <stop offset=\"10%\" style=\"stop-color:white; stop-opacity:1;\" />\n <stop offset=\"50%\" style=\"stop-color:white; stop-opacity:1;\" />\n <stop offset=\"90%\" style=\"stop-color:white; stop-opacity:1;\" />\n <stop offset=\"100%\" style=\"stop-color:black; stop-opacity:1;\" />\n </linearGradient>\n <rect x=\"${-this.width / 2}\" y=\"${-70}\" \n width=\"${this.width}\" height=\"${32}\"\n fill=\"url(#fadeGradient)\" />\n </mask>\n `;\n }\n\n private renderLabels(scale: number): SVGTemplateResult[] {\n const labels: SVGTemplateResult[] = [];\n\n for (const l of this.labels) {\n labels.push(\n svg`<g transform=\"translate(${-this.rotation * this.tickmarkSpacing}, ${-6 / scale})\">\n <text x=${l.x} y=${l.y} class=\"label\" fill=${'var(--instrument-tick-mark-secondary-color)'}>\n ${l.text}\n </text>\n </g>`\n );\n }\n\n return labels;\n }\n\n private watchFace(): SVGTemplateResult {\n const strokeWidth = 1;\n\n return svg`\n ${this.renderClipPath()}\n ${this.renderClipPath(-40)}\n <g clip-path=\"url(#frameClipPath)\">\n ${rect('frame-track', {\n width: this.width,\n height: this.trackHeight,\n y: this.height / 2 - this.trackHeight,\n strokeWidth: strokeWidth,\n strokeColor: 'var(--instrument-frame-secondary-color)',\n strokePosition: 'inside',\n fillColor: 'var(--instrument-frame-secondary-color)',\n borderRadius: 0,\n })}\n ${rect('frame-ticks', {\n width: this.width,\n height: this.ticksHeight,\n y: this.height / 2 - this.trackHeight - this.ticksHeight,\n strokeWidth: strokeWidth,\n strokeColor: 'var(--instrument-frame-primary-color)',\n strokePosition: 'inside',\n fillColor: 'var(--instrument-frame-primary-color)',\n borderRadius: 0,\n })}\n </g>\n ${rect('frame-outline', {\n width: this.width,\n height: this.height,\n strokeWidth: strokeWidth,\n strokeColor: 'var(--instrument-frame-tertiary-color)',\n strokePosition: 'inside',\n fillColor: 'none',\n borderRadius: this.borderRadius,\n })}\n `;\n }\n\n override render() {\n const width = (this.width / 2 + this.padding) * 2;\n const viewBox = `-${width / 2} -${this.height / 2} ${width} ${this.height}`;\n const scale = this.clientWidth / width;\n\n return html`\n <svg\n width=\"100%\"\n height=\"100%\"\n viewBox=${viewBox}\n style=\"--scale: ${scale}\"\n >\n ${this.watchFace()} ${this.renderLabelMask()} ${this.FOVIndicator}\n\n <g clip-path=\"url(#frameClipPath)\">\n ${this.tickmarks.map(\n (t) => svg`\n <g transform=\"translate(${-this.rotation * this.tickmarkSpacing}, 0)\">\n ${tickmark(t.angle, t.type, TickmarkStyle.regular)}\n </g>\n `\n )}\n </g>\n\n <g mask=\"url(#labelMask)\">\n ${this.renderLabels(scale)}\n </svg>\n `;\n }\n\n static override styles = unsafeCSS(compentStyle);\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'obc-watch-flat': ObcWatchFlat;\n }\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"watch-flat.js","sources":["../../../src/navigation-instruments/watch-flat/watch-flat.ts"],"sourcesContent":["import {\n LitElement,\n PropertyValues,\n SVGTemplateResult,\n html,\n nothing,\n svg,\n unsafeCSS,\n} from 'lit';\nimport {property} from 'lit/decorators.js';\nimport compentStyle from './watch-flat.css?inline';\nimport {Tickmark, TickmarkStyle, tickmark} from './tickmark-flat.js';\nimport {rect} from '../../svghelpers/rectangular.js';\nimport {Label} from '../compass-flat/compass-flat.js';\nimport {customElement} from '../../decorator.js';\nimport {Priority} from '../types.js';\nimport {\n RotType,\n LinearRotPosition,\n renderLinearRotDots,\n renderLinearRotBarStatic,\n renderLinearRotBarDots,\n LINEAR_DOT_ANGLE_SPACING,\n} from '../rate-of-turn/rot-renderer.js';\nimport {\n RateOfTurnController,\n disposeRotController,\n} from '../rate-of-turn/rate-of-turn.controller.js';\n\nexport {RotType, LinearRotPosition};\n\n@customElement('obc-watch-flat')\nexport class ObcWatchFlat extends LitElement {\n @property({type: Number}) width = 352;\n @property({type: Number}) height = 72;\n @property({type: Number}) padding = 0;\n @property({type: Number}) rotation = 0;\n @property({type: Number}) tickmarkSpacing = 0;\n @property({type: Number}) angleSetpoint: number | undefined;\n @property({type: Array, attribute: false}) tickmarks: Tickmark[] = [];\n @property({type: Array, attribute: false}) labels: Label[] = [];\n @property({type: Array, attribute: false}) FOVIndicator: SVGTemplateResult[] =\n [];\n @property({type: Number}) trackHeight = (2 / 3) * this.height;\n @property({type: Number}) ticksHeight = this.height - this.trackHeight;\n @property({type: Number}) borderRadius = 8;\n @property({type: Boolean}) bottomBar = false;\n\n @property({type: String}) rotType: RotType | undefined;\n @property({type: String}) rotPosition: LinearRotPosition =\n LinearRotPosition.track;\n /** Bar start position in SVG user-space x-coordinates (center-origin). Computed by the parent instrument. */\n @property({type: Number}) rotStartX: number = 0;\n /** Bar end position in SVG user-space x-coordinates (center-origin). Computed by the parent instrument. */\n @property({type: Number}) rotEndX: number = 0;\n /**\n * Pixel spacing between adjacent dots in the linear ROT strip.\n * Must be > 0 to enable animation; the default `0` intentionally disables\n * the spinning dots so the parent instrument must supply a meaningful value\n * derived from the current scale (e.g. `LINEAR_DOT_ANGLE_SPACING * translationScale`).\n */\n @property({type: Number}) rotDotSpacing: number = 0;\n @property({type: String}) rotPriority: Priority = Priority.regular;\n\n @property({type: Number})\n set rotationsPerMinute(value: number) {\n this._rotationsPerMinute = value;\n if (this._rotController) {\n this._rotController.rotationsPerMinute = value;\n }\n }\n get rotationsPerMinute() {\n return this._rotationsPerMinute;\n }\n\n private _rotationsPerMinute = 0;\n private _rotController?: RateOfTurnController;\n\n private get totalHeight(): number {\n return this.bottomBar ? this.height + this.ticksHeight : this.height;\n }\n\n private renderClipPath(offsetY: number = 0): SVGTemplateResult {\n return svg`\n <clipPath id=\"frameClipPath${offsetY === 0 ? '' : 'Tickmarks'}\">\n <rect x=\"${-this.width / 2}\" y=\"${-this.totalHeight / 2 + offsetY}\" \n width=\"${this.width}\" height=\"${this.totalHeight}\" \n rx=\"${this.borderRadius}\" />\n </clipPath>\n `;\n }\n\n private renderLabelMask(): SVGTemplateResult {\n return svg`\n <mask id=\"labelMask\">\n <rect x=\"${-this.width / 2}\" y=\"${-70}\" \n width=\"${this.width}\" height=\"${32}\"\n />\n <linearGradient id=\"fadeGradient\" gradientUnits=\"userSpaceOnUse\"\n x1=\"${-this.width / 2}\" y1=\"0\" x2=\"${this.width / 2}\" y2=\"0\">\n <stop offset=\"0%\" style=\"stop-color:black; stop-opacity:1;\" />\n <stop offset=\"10%\" style=\"stop-color:white; stop-opacity:1;\" />\n <stop offset=\"50%\" style=\"stop-color:white; stop-opacity:1;\" />\n <stop offset=\"90%\" style=\"stop-color:white; stop-opacity:1;\" />\n <stop offset=\"100%\" style=\"stop-color:black; stop-opacity:1;\" />\n </linearGradient>\n <rect x=\"${-this.width / 2}\" y=\"${-70}\" \n width=\"${this.width}\" height=\"${32}\"\n fill=\"url(#fadeGradient)\" />\n </mask>\n `;\n }\n\n private renderLabels(scale: number): SVGTemplateResult[] {\n const labels: SVGTemplateResult[] = [];\n\n for (const l of this.labels) {\n labels.push(\n svg`<g transform=\"translate(${-this.rotation * this.tickmarkSpacing}, ${-6 / scale})\">\n <text x=${l.x} y=${l.y} class=\"label\" fill=${'var(--instrument-tick-mark-secondary-color)'}>\n ${l.text}\n </text>\n </g>`\n );\n }\n\n return labels;\n }\n\n private watchFace(): SVGTemplateResult {\n const strokeWidth = 1;\n const th = this.totalHeight;\n const topTicksY = -th / 2;\n\n return svg`\n ${this.renderClipPath()}\n ${this.renderClipPath(-40)}\n <g clip-path=\"url(#frameClipPath)\">\n ${rect('frame-track', {\n width: this.width,\n height: this.trackHeight,\n y:\n th / 2 - this.trackHeight - (this.bottomBar ? this.ticksHeight : 0),\n strokeWidth: strokeWidth,\n strokeColor: 'var(--instrument-frame-secondary-color)',\n strokePosition: 'inside',\n fillColor: 'var(--instrument-frame-secondary-color)',\n borderRadius: 0,\n })}\n ${rect('frame-ticks', {\n width: this.width,\n height: this.ticksHeight,\n y: topTicksY,\n strokeWidth: strokeWidth,\n strokeColor: 'var(--instrument-frame-primary-color)',\n strokePosition: 'inside',\n fillColor: 'var(--instrument-frame-primary-color)',\n borderRadius: 0,\n })}\n ${\n this.bottomBar\n ? rect('frame-bottom-bar', {\n width: this.width,\n height: this.ticksHeight,\n y: th / 2 - this.ticksHeight,\n strokeWidth: strokeWidth,\n strokeColor: 'var(--instrument-frame-primary-color)',\n strokePosition: 'inside',\n fillColor: 'var(--instrument-frame-primary-color)',\n borderRadius: 0,\n })\n : nothing\n }\n </g>\n ${rect('frame-outline', {\n width: this.width,\n height: th,\n strokeWidth: strokeWidth,\n strokeColor: 'var(--instrument-frame-tertiary-color)',\n strokePosition: 'inside',\n fillColor: 'none',\n borderRadius: this.borderRadius,\n })}\n `;\n }\n\n // ---------------------------------------------------------------------------\n // ROT (Rate of Turn) — linear\n // ---------------------------------------------------------------------------\n\n private getRotTrackY(): number {\n const th = this.totalHeight;\n if (this.rotPosition === LinearRotPosition.scale) {\n return -th / 2 + this.ticksHeight / 2;\n }\n if (this.bottomBar) {\n return th / 2 - this.ticksHeight / 2;\n }\n return this.height / 2 - this.trackHeight / 2;\n }\n\n private getRotColors(): {\n dotColor: string;\n barBgColor: string;\n endDotFill: string;\n endDotStroke: string;\n } {\n const isEnhanced = this.rotPriority === Priority.enhanced;\n return {\n dotColor: isEnhanced\n ? 'var(--instrument-enhanced-tertiary-color)'\n : 'var(--instrument-regular-tertiary-color)',\n barBgColor: isEnhanced\n ? 'var(--instrument-enhanced-secondary-color)'\n : 'var(--instrument-regular-secondary-color)',\n endDotFill: 'var(--border-silhouette-color)',\n endDotStroke: isEnhanced\n ? 'var(--instrument-enhanced-secondary-color)'\n : 'var(--instrument-regular-secondary-color)',\n };\n }\n\n private renderRot(): SVGTemplateResult | typeof nothing {\n if (!this.rotType) return nothing;\n\n const trackY = this.getRotTrackY();\n const {dotColor, barBgColor, endDotFill, endDotStroke} =\n this.getRotColors();\n const canAnimateDots = this.rotDotSpacing > 0;\n\n if (this.rotType === RotType.bar) {\n const hasBar = Math.abs(this.rotEndX - this.rotStartX) >= 1;\n return svg`\n ${renderLinearRotBarStatic({\n startX: this.rotStartX,\n endX: this.rotEndX,\n color: dotColor,\n barColor: barBgColor,\n trackY,\n endDotFill,\n endDotStroke,\n maskId: 'rot-bar-mask-linear',\n })}\n ${\n hasBar && canAnimateDots\n ? svg`<g clip-path=\"url(#rot-bar-mask-linear)\">\n <g id=\"rot-spinner\">\n ${renderLinearRotBarDots(dotColor, trackY, this.rotDotSpacing, this.width)}\n </g>\n </g>`\n : nothing\n }\n `;\n }\n\n const dotsColor =\n this.rotPriority === Priority.enhanced\n ? 'var(--instrument-enhanced-secondary-color)'\n : 'var(--instrument-regular-secondary-color)';\n return canAnimateDots\n ? svg`\n <g id=\"rot-spinner\">\n ${renderLinearRotDots(dotsColor, trackY, this.rotDotSpacing, this.width)}\n </g>\n `\n : nothing;\n }\n\n override updated(changed: PropertyValues): void {\n super.updated(changed);\n const el = this.rotType\n ? this.renderRoot.querySelector('#rot-spinner')\n : null;\n\n if (!el) {\n this._rotController = disposeRotController(this, this._rotController);\n return;\n }\n\n const cyclePx = 360 * (this.rotDotSpacing / LINEAR_DOT_ANGLE_SPACING);\n\n if (!this._rotController || this._rotController.el !== el) {\n this._rotController = disposeRotController(this, this._rotController);\n this._rotController = new RateOfTurnController(\n this,\n el,\n this._rotationsPerMinute,\n cyclePx\n );\n } else {\n this._rotController.cyclePx = cyclePx;\n }\n }\n\n override disconnectedCallback(): void {\n super.disconnectedCallback();\n this._rotController = disposeRotController(this, this._rotController);\n }\n\n override render() {\n const width = (this.width / 2 + this.padding) * 2;\n const th = this.totalHeight;\n const viewBox = `-${width / 2} -${th / 2} ${width} ${th}`;\n const scale = this.clientWidth / width;\n\n const contentOffsetY = this.bottomBar ? -this.ticksHeight / 2 : 0;\n\n return html`\n <svg\n width=\"100%\"\n height=\"100%\"\n viewBox=${viewBox}\n style=\"--scale: ${scale}\"\n >\n ${this.watchFace()} ${this.renderLabelMask()}\n\n <g transform=\"translate(0, ${contentOffsetY})\">\n <g clip-path=\"url(#frameClipPath)\">\n ${this.tickmarks.map(\n (t) => svg`\n <g transform=\"translate(${-this.rotation * this.tickmarkSpacing}, 0)\">\n ${tickmark(t.angle, t.type, TickmarkStyle.regular)}\n </g>\n `\n )}\n </g>\n\n <g mask=\"url(#labelMask)\">${this.renderLabels(scale)}</g>\n </g>\n\n ${this.FOVIndicator}\n\n <g clip-path=\"url(#frameClipPath)\">${this.renderRot()}</g>\n </svg>\n `;\n }\n\n static override styles = unsafeCSS(compentStyle);\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'obc-watch-flat': ObcWatchFlat;\n }\n}\n"],"names":[],"mappings":"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"}
|