@oicl/openbridge-webcomponents 2.0.0-next.101 → 2.0.0-next.103
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bundle/openbridge-webcomponents.bundle.js +580 -143
- package/bundle/openbridge-webcomponents.bundle.js.map +1 -1
- package/custom-elements.json +629 -407
- package/dist/bars-graphs/donut-chart/donut-chart.d.ts +18 -16
- package/dist/bars-graphs/donut-chart/donut-chart.d.ts.map +1 -1
- package/dist/bars-graphs/donut-chart/donut-chart.js.map +1 -1
- package/dist/bars-graphs/pie-chart/pie-chart.d.ts +14 -12
- package/dist/bars-graphs/pie-chart/pie-chart.d.ts.map +1 -1
- package/dist/bars-graphs/pie-chart/pie-chart.js.map +1 -1
- package/dist/bars-graphs/polar-chart/polar-chart.d.ts +19 -16
- package/dist/bars-graphs/polar-chart/polar-chart.d.ts.map +1 -1
- package/dist/bars-graphs/polar-chart/polar-chart.js.map +1 -1
- package/dist/bars-graphs/radial-bar-chart/radial-bar-chart.d.ts +8 -8
- package/dist/bars-graphs/radial-bar-chart/radial-bar-chart.d.ts.map +1 -1
- package/dist/bars-graphs/radial-bar-chart/radial-bar-chart.js.map +1 -1
- package/dist/building-blocks/chart-line/chart-line-base.d.ts +8 -25
- package/dist/building-blocks/chart-line/chart-line-base.d.ts.map +1 -1
- package/dist/building-blocks/chart-line/chart-line-base.js.map +1 -1
- package/dist/building-blocks/instrument-radial/instrument-radial.d.ts +22 -2
- package/dist/building-blocks/instrument-radial/instrument-radial.d.ts.map +1 -1
- package/dist/building-blocks/instrument-radial/instrument-radial.js +61 -37
- package/dist/building-blocks/instrument-radial/instrument-radial.js.map +1 -1
- package/dist/integration-systems/integration-bar/integration-bar.d.ts +20 -24
- package/dist/integration-systems/integration-bar/integration-bar.d.ts.map +1 -1
- package/dist/integration-systems/integration-bar/integration-bar.js.map +1 -1
- package/dist/integration-systems/integration-button/integration-button.d.ts +15 -13
- package/dist/integration-systems/integration-button/integration-button.d.ts.map +1 -1
- package/dist/integration-systems/integration-button/integration-button.js.map +1 -1
- package/dist/navigation-instruments/azimuth-thruster/azimuth-thruster.d.ts +14 -0
- package/dist/navigation-instruments/azimuth-thruster/azimuth-thruster.d.ts.map +1 -1
- package/dist/navigation-instruments/azimuth-thruster/azimuth-thruster.js +30 -11
- package/dist/navigation-instruments/azimuth-thruster/azimuth-thruster.js.map +1 -1
- package/dist/navigation-instruments/compass/compass.d.ts +68 -31
- package/dist/navigation-instruments/compass/compass.d.ts.map +1 -1
- package/dist/navigation-instruments/compass/compass.js +36 -16
- package/dist/navigation-instruments/compass/compass.js.map +1 -1
- package/dist/navigation-instruments/compass-flat/compass-flat.d.ts +8 -9
- package/dist/navigation-instruments/compass-flat/compass-flat.d.ts.map +1 -1
- package/dist/navigation-instruments/compass-flat/compass-flat.js.map +1 -1
- package/dist/navigation-instruments/compass-sector/compass-sector.d.ts.map +1 -1
- package/dist/navigation-instruments/compass-sector/compass-sector.js.map +1 -1
- package/dist/navigation-instruments/gauge-radial/gauge-radial.css.js +34 -2
- package/dist/navigation-instruments/gauge-radial/gauge-radial.css.js.map +1 -1
- package/dist/navigation-instruments/gauge-radial/gauge-radial.d.ts +15 -0
- package/dist/navigation-instruments/gauge-radial/gauge-radial.d.ts.map +1 -1
- package/dist/navigation-instruments/gauge-radial/gauge-radial.js +35 -1
- package/dist/navigation-instruments/gauge-radial/gauge-radial.js.map +1 -1
- package/dist/navigation-instruments/gauge-trend/gauge-trend.d.ts +0 -5
- package/dist/navigation-instruments/gauge-trend/gauge-trend.d.ts.map +1 -1
- package/dist/navigation-instruments/gauge-trend/gauge-trend.js.map +1 -1
- package/dist/navigation-instruments/graph-mini/graph-mini.d.ts +1 -1
- package/dist/navigation-instruments/graph-mini/graph-mini.d.ts.map +1 -1
- package/dist/navigation-instruments/graph-mini/graph-mini.js.map +1 -1
- package/dist/navigation-instruments/heading/heading.d.ts +19 -1
- package/dist/navigation-instruments/heading/heading.d.ts.map +1 -1
- package/dist/navigation-instruments/heading/heading.js +34 -16
- package/dist/navigation-instruments/heading/heading.js.map +1 -1
- package/dist/navigation-instruments/indicator-graph/indicator-graph.d.ts +1 -1
- package/dist/navigation-instruments/indicator-graph/indicator-graph.d.ts.map +1 -1
- package/dist/navigation-instruments/indicator-graph/indicator-graph.js.map +1 -1
- package/dist/navigation-instruments/rudder/rudder.d.ts +15 -2
- package/dist/navigation-instruments/rudder/rudder.d.ts.map +1 -1
- package/dist/navigation-instruments/rudder/rudder.js +36 -26
- package/dist/navigation-instruments/rudder/rudder.js.map +1 -1
- package/dist/navigation-instruments/speed-gauge/speed-gauge.d.ts +15 -1
- package/dist/navigation-instruments/speed-gauge/speed-gauge.d.ts.map +1 -1
- package/dist/navigation-instruments/speed-gauge/speed-gauge.js +31 -3
- package/dist/navigation-instruments/speed-gauge/speed-gauge.js.map +1 -1
- package/dist/navigation-instruments/watch/watch.d.ts +45 -17
- package/dist/navigation-instruments/watch/watch.d.ts.map +1 -1
- package/dist/navigation-instruments/watch/watch.js +53 -38
- package/dist/navigation-instruments/watch/watch.js.map +1 -1
- package/dist/svghelpers/radial-frame.d.ts +122 -0
- package/dist/svghelpers/radial-frame.d.ts.map +1 -0
- package/dist/svghelpers/radial-frame.js +259 -0
- package/dist/svghelpers/radial-frame.js.map +1 -0
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"indicator-graph.d.ts","sourceRoot":"","sources":["../../../src/navigation-instruments/indicator-graph/indicator-graph.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,UAAU,EAAE,cAAc,EAAkB,MAAM,KAAK,CAAC;AAMhE,oBAAY,qBAAqB;IAC/B,KAAK,UAAU;IACf,MAAM,WAAW;IACjB,KAAK,UAAU;CAChB;AAED,oBAAY,yBAAyB;IACnC,OAAO,YAAY;IACnB,QAAQ,aAAa;CACtB;AAGD,MAAM,WAAW,uBAAuB;IACtC,IAAI,CAAC,EAAE,qBAAqB,CAAC;IAC7B,QAAQ,CAAC,EAAE,yBAAyB,CAAC;IACrC,CAAC,CAAC,EAAE;QAAC,GAAG,CAAC,EAAE,MAAM,CAAC;QAAC,GAAG,CAAC,EAAE,MAAM,CAAC;QAAC,YAAY,CAAC,EAAE,OAAO,CAAA;KAAC,CAAC;CAC1D;AAED
|
|
1
|
+
{"version":3,"file":"indicator-graph.d.ts","sourceRoot":"","sources":["../../../src/navigation-instruments/indicator-graph/indicator-graph.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,UAAU,EAAE,cAAc,EAAkB,MAAM,KAAK,CAAC;AAMhE,oBAAY,qBAAqB;IAC/B,KAAK,UAAU;IACf,MAAM,WAAW;IACjB,KAAK,UAAU;CAChB;AAED,oBAAY,yBAAyB;IACnC,OAAO,YAAY;IACnB,QAAQ,aAAa;CACtB;AAGD,MAAM,WAAW,uBAAuB;IACtC,IAAI,CAAC,EAAE,qBAAqB,CAAC;IAC7B,QAAQ,CAAC,EAAE,yBAAyB,CAAC;IACrC,CAAC,CAAC,EAAE;QAAC,GAAG,CAAC,EAAE,MAAM,CAAC;QAAC,GAAG,CAAC,EAAE,MAAM,CAAC;QAAC,YAAY,CAAC,EAAE,OAAO,CAAA;KAAC,CAAC;CAC1D;AAED;;;;;GAKG;AACH,qBACa,iBAAkB,SAAQ,UAAU;IAC/C,kGAAkG;IAElG,IAAI,EAAE,CAAC,MAAM,EAAE,EAAE,MAAM,EAAE,CAAC,CAAY;IAGtC,MAAM,EAAE,uBAAuB,CAAM;IAGrC,OAAO,CAAC,KAAK,CAAkB;IAG/B,OAAO,CAAC,CAAC,CAAiC;IAG1C,OAAO,CAAC,SAAS,CAAiC;IAElD,OAAO,CAAC,KAAK,CAAsB;IACnC,OAAO,CAAC,cAAc,CAA+B;IAErD,OAAO,CAAC,WAAW;IAKV,YAAY;IAmCZ,oBAAoB;IAQ7B,OAAO,CAAC,UAAU;IAWlB,OAAO,CAAC,MAAM;IAed,OAAO,KAAK,cAAc,GAEzB;IAED,OAAO,KAAK,kBAAkB,GAE7B;IAED,OAAO,CAAC,eAAe;IAWvB,OAAO,CAAC,eAAe;IASvB,aAAa;IAUb,OAAO,CAAC,OAAO;IAef,OAAO,CAAC,cAAc;IAab,OAAO,CAAC,iBAAiB,EAAE,cAAc;IAQzC,MAAM;IAuBf,OAAgB,MAAM,0BAA2B;CAClD;AAED,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,qBAAqB,EAAE,iBAAiB,CAAC;KAC1C;CACF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"indicator-graph.js","sources":["../../../src/navigation-instruments/indicator-graph/indicator-graph.ts"],"sourcesContent":["import {LitElement, PropertyValues, html, unsafeCSS} from 'lit';\nimport {property, query, state} from 'lit/decorators.js';\nimport compentStyle from './indicator-graph.css?inline';\nimport uPlot from 'uplot';\nimport {customElement} from '../../decorator.js';\n\nexport enum ObcIndicatorGraphSize {\n small = 'small',\n medium = 'medium',\n large = 'large',\n}\n\nexport enum ObcIndicatorGraphPriority {\n regular = 'regular',\n enhanced = 'enhanced',\n}\n\n// showZeroLine is defaulted to true\nexport interface ObcIndicatorGraphLayout {\n size?: ObcIndicatorGraphSize;\n priority?: ObcIndicatorGraphPriority;\n y?: {min?: number; max?: number; showZeroLine?: boolean};\n}\n\n/**\n * @element obc-indicator-graph\n * @description A mini graph component\n *\n * @property {Array} data - The data to display in the graph, first array is the x values, second array is the y values\n * @beta\n */\n@customElement('obc-indicator-graph')\nexport class ObcIndicatorGraph extends LitElement {\n @property({type: Array})\n data: [number[], number[]] = [[], []];\n\n @property({type: Object})\n layout: ObcIndicatorGraphLayout = {};\n\n @query('#chart')\n private chart!: HTMLDivElement;\n\n @state()\n private y: number | undefined = undefined;\n\n @state()\n private zeroLineY: number | undefined = undefined;\n\n private uplot: uPlot | null = null;\n private resizeObserver: ResizeObserver | null = null;\n\n private getCssColor(name: string) {\n const color = getComputedStyle(this).getPropertyValue(name).trim();\n return color;\n }\n\n override firstUpdated() {\n const opts = {\n width: this.chart.clientWidth,\n height: this.chart.clientHeight,\n scales: {\n x: {time: false, show: false},\n y: {\n auto: true,\n show: false,\n range: this._range.bind(this),\n },\n },\n series: [\n {},\n {\n stroke: this._getStrokeColor(),\n width: this._getStrokeWidth(),\n points: {show: false},\n },\n ],\n axes: [\n {show: false},\n {ticks: {show: false}, show: false, grid: {show: false}},\n ],\n legend: {show: false},\n cursor: {show: false},\n };\n\n this.uplot = new uPlot(opts, this.data, this.chart);\n requestAnimationFrame(() => this.updateY());\n\n this.resizeObserver = new ResizeObserver(() => this.updateSize());\n this.resizeObserver.observe(this.chart);\n }\n\n override disconnectedCallback() {\n super.disconnectedCallback();\n this.resizeObserver?.disconnect();\n this.resizeObserver = null;\n this.uplot?.destroy();\n this.uplot = null;\n }\n\n private updateSize() {\n if (!this.uplot) {\n return;\n }\n this.uplot.setSize({\n width: this.chart.clientWidth,\n height: this.chart.clientHeight,\n });\n this.updateY();\n }\n\n private _range(\n _self: uPlot,\n initMin: number,\n initMax: number,\n _scaleKey: string\n ): [number, number] {\n const {min: minY, max: maxY} = this.layout.y ?? {};\n const range = maxY ?? initMax - (minY ?? initMin);\n let min = minY ?? initMin - range * 0.1;\n if (minY === undefined && this.layout.y?.showZeroLine !== false) {\n min = Math.min(0, min);\n }\n return [min, maxY ?? initMax + range * 0.1] as [number, number];\n }\n\n private get _effectiveSize() {\n return this.layout.size ?? ObcIndicatorGraphSize.medium;\n }\n\n private get _effectivePriority() {\n return this.layout.priority ?? ObcIndicatorGraphPriority.regular;\n }\n\n private _getStrokeWidth() {\n switch (this._effectiveSize) {\n case ObcIndicatorGraphSize.small:\n return 1;\n case ObcIndicatorGraphSize.medium:\n return 1.5;\n case ObcIndicatorGraphSize.large:\n return 2;\n }\n }\n\n private _getStrokeColor() {\n switch (this._effectivePriority) {\n case ObcIndicatorGraphPriority.regular:\n return this.getCssColor('--element-neutral-color');\n case ObcIndicatorGraphPriority.enhanced:\n return this.getCssColor('--element-neutral-enhanced-color');\n }\n }\n\n updatePalette() {\n if (!this.uplot) {\n return;\n }\n const series = this.uplot.series[1];\n series.stroke = () => this._getStrokeColor();\n series.width = this._getStrokeWidth();\n this.uplot.redraw();\n }\n\n private updateY() {\n if (!this.uplot) {\n return;\n }\n const lastY = this.data[1][this.data[1].length - 1];\n // @ts-expect-error - valToPct is not a property of the Scale interface\n const yRatio = this.uplot.scales.y.valToPct(lastY);\n if (yRatio < 0 || yRatio > 1) {\n this.y = undefined;\n } else {\n this.y = yRatio * this.chart.clientHeight;\n }\n this.updateZeroLine();\n }\n\n private updateZeroLine() {\n if (!this.uplot) {\n return;\n }\n // @ts-expect-error - valToPct is not a property of the Scale interface\n const yRatio = this.uplot.scales.y.valToPct(0);\n if (yRatio < 0 || yRatio > 1) {\n this.zeroLineY = undefined;\n return;\n }\n this.zeroLineY = yRatio * this.chart.clientHeight;\n }\n\n override updated(changedProperties: PropertyValues) {\n if (changedProperties.has('data') || changedProperties.has('layout')) {\n this.updatePalette();\n this.uplot?.setData(this.data);\n requestAnimationFrame(() => this.updateY());\n }\n }\n\n override render() {\n return html`\n <div\n class=\"chart-container ${this._effectivePriority} ${this\n ._effectiveSize}\"\n >\n <div id=\"chart\"></div>\n <div\n id=\"zero-line\"\n style=\"transform: translateY(${-(this.zeroLineY ?? 0)}px);\n display: ${this.zeroLineY !== undefined ? 'block' : 'none'};\n \"\n ></div>\n <div\n id=\"dot\"\n style=\"transform: translateY(${-(this.y ?? 0)}px);\n display: ${this.y !== undefined ? 'block' : 'none'};\n \"\n ></div>\n </div>\n `;\n }\n\n static override styles = unsafeCSS(compentStyle);\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'obc-indicator-graph': ObcIndicatorGraph;\n }\n}\n"],"names":["ObcIndicatorGraphSize","ObcIndicatorGraphPriority"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"indicator-graph.js","sources":["../../../src/navigation-instruments/indicator-graph/indicator-graph.ts"],"sourcesContent":["import {LitElement, PropertyValues, html, unsafeCSS} from 'lit';\nimport {property, query, state} from 'lit/decorators.js';\nimport compentStyle from './indicator-graph.css?inline';\nimport uPlot from 'uplot';\nimport {customElement} from '../../decorator.js';\n\nexport enum ObcIndicatorGraphSize {\n small = 'small',\n medium = 'medium',\n large = 'large',\n}\n\nexport enum ObcIndicatorGraphPriority {\n regular = 'regular',\n enhanced = 'enhanced',\n}\n\n// showZeroLine is defaulted to true\nexport interface ObcIndicatorGraphLayout {\n size?: ObcIndicatorGraphSize;\n priority?: ObcIndicatorGraphPriority;\n y?: {min?: number; max?: number; showZeroLine?: boolean};\n}\n\n/**\n * @element obc-indicator-graph\n * @description A mini graph component\n *\n * @beta\n */\n@customElement('obc-indicator-graph')\nexport class ObcIndicatorGraph extends LitElement {\n /** The data to display in the graph, first array is the x values, second array is the y values */\n @property({type: Array})\n data: [number[], number[]] = [[], []];\n\n @property({type: Object})\n layout: ObcIndicatorGraphLayout = {};\n\n @query('#chart')\n private chart!: HTMLDivElement;\n\n @state()\n private y: number | undefined = undefined;\n\n @state()\n private zeroLineY: number | undefined = undefined;\n\n private uplot: uPlot | null = null;\n private resizeObserver: ResizeObserver | null = null;\n\n private getCssColor(name: string) {\n const color = getComputedStyle(this).getPropertyValue(name).trim();\n return color;\n }\n\n override firstUpdated() {\n const opts = {\n width: this.chart.clientWidth,\n height: this.chart.clientHeight,\n scales: {\n x: {time: false, show: false},\n y: {\n auto: true,\n show: false,\n range: this._range.bind(this),\n },\n },\n series: [\n {},\n {\n stroke: this._getStrokeColor(),\n width: this._getStrokeWidth(),\n points: {show: false},\n },\n ],\n axes: [\n {show: false},\n {ticks: {show: false}, show: false, grid: {show: false}},\n ],\n legend: {show: false},\n cursor: {show: false},\n };\n\n this.uplot = new uPlot(opts, this.data, this.chart);\n requestAnimationFrame(() => this.updateY());\n\n this.resizeObserver = new ResizeObserver(() => this.updateSize());\n this.resizeObserver.observe(this.chart);\n }\n\n override disconnectedCallback() {\n super.disconnectedCallback();\n this.resizeObserver?.disconnect();\n this.resizeObserver = null;\n this.uplot?.destroy();\n this.uplot = null;\n }\n\n private updateSize() {\n if (!this.uplot) {\n return;\n }\n this.uplot.setSize({\n width: this.chart.clientWidth,\n height: this.chart.clientHeight,\n });\n this.updateY();\n }\n\n private _range(\n _self: uPlot,\n initMin: number,\n initMax: number,\n _scaleKey: string\n ): [number, number] {\n const {min: minY, max: maxY} = this.layout.y ?? {};\n const range = maxY ?? initMax - (minY ?? initMin);\n let min = minY ?? initMin - range * 0.1;\n if (minY === undefined && this.layout.y?.showZeroLine !== false) {\n min = Math.min(0, min);\n }\n return [min, maxY ?? initMax + range * 0.1] as [number, number];\n }\n\n private get _effectiveSize() {\n return this.layout.size ?? ObcIndicatorGraphSize.medium;\n }\n\n private get _effectivePriority() {\n return this.layout.priority ?? ObcIndicatorGraphPriority.regular;\n }\n\n private _getStrokeWidth() {\n switch (this._effectiveSize) {\n case ObcIndicatorGraphSize.small:\n return 1;\n case ObcIndicatorGraphSize.medium:\n return 1.5;\n case ObcIndicatorGraphSize.large:\n return 2;\n }\n }\n\n private _getStrokeColor() {\n switch (this._effectivePriority) {\n case ObcIndicatorGraphPriority.regular:\n return this.getCssColor('--element-neutral-color');\n case ObcIndicatorGraphPriority.enhanced:\n return this.getCssColor('--element-neutral-enhanced-color');\n }\n }\n\n updatePalette() {\n if (!this.uplot) {\n return;\n }\n const series = this.uplot.series[1];\n series.stroke = () => this._getStrokeColor();\n series.width = this._getStrokeWidth();\n this.uplot.redraw();\n }\n\n private updateY() {\n if (!this.uplot) {\n return;\n }\n const lastY = this.data[1][this.data[1].length - 1];\n // @ts-expect-error - valToPct is not a property of the Scale interface\n const yRatio = this.uplot.scales.y.valToPct(lastY);\n if (yRatio < 0 || yRatio > 1) {\n this.y = undefined;\n } else {\n this.y = yRatio * this.chart.clientHeight;\n }\n this.updateZeroLine();\n }\n\n private updateZeroLine() {\n if (!this.uplot) {\n return;\n }\n // @ts-expect-error - valToPct is not a property of the Scale interface\n const yRatio = this.uplot.scales.y.valToPct(0);\n if (yRatio < 0 || yRatio > 1) {\n this.zeroLineY = undefined;\n return;\n }\n this.zeroLineY = yRatio * this.chart.clientHeight;\n }\n\n override updated(changedProperties: PropertyValues) {\n if (changedProperties.has('data') || changedProperties.has('layout')) {\n this.updatePalette();\n this.uplot?.setData(this.data);\n requestAnimationFrame(() => this.updateY());\n }\n }\n\n override render() {\n return html`\n <div\n class=\"chart-container ${this._effectivePriority} ${this\n ._effectiveSize}\"\n >\n <div id=\"chart\"></div>\n <div\n id=\"zero-line\"\n style=\"transform: translateY(${-(this.zeroLineY ?? 0)}px);\n display: ${this.zeroLineY !== undefined ? 'block' : 'none'};\n \"\n ></div>\n <div\n id=\"dot\"\n style=\"transform: translateY(${-(this.y ?? 0)}px);\n display: ${this.y !== undefined ? 'block' : 'none'};\n \"\n ></div>\n </div>\n `;\n }\n\n static override styles = unsafeCSS(compentStyle);\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'obc-indicator-graph': ObcIndicatorGraph;\n }\n}\n"],"names":["ObcIndicatorGraphSize","ObcIndicatorGraphPriority"],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { LitElement, nothing } from 'lit';
|
|
1
|
+
import { LitElement, PropertyValues, nothing } from 'lit';
|
|
2
2
|
import { TickmarkStyle } from '../watch/tickmark.js';
|
|
3
3
|
import { InstrumentState, Priority } from '../types.js';
|
|
4
4
|
import { AngleAdvice } from '../watch/advice.js';
|
|
@@ -80,8 +80,21 @@ export declare class ObcRudder extends ObcRudder_base {
|
|
|
80
80
|
tickmarkStyle: TickmarkStyle;
|
|
81
81
|
advices: AngleAdvice[];
|
|
82
82
|
zoomToFitArc: boolean;
|
|
83
|
+
/**
|
|
84
|
+
* Outer-ring diameter in CSS pixels. When set, the instrument renders at a
|
|
85
|
+
* fixed intrinsic size derived from the ring, arc shape and label reserve —
|
|
86
|
+
* so instruments sharing the same value have identical ring circumference
|
|
87
|
+
* regardless of label width or arc extent (like obc-donut-chart's
|
|
88
|
+
* fixedHeight). When unset (default), the instrument fills its container.
|
|
89
|
+
*/
|
|
90
|
+
faceDiameter: number | undefined;
|
|
83
91
|
private _radiusOffset;
|
|
84
|
-
private
|
|
92
|
+
private _frame;
|
|
93
|
+
/** Whether the host size styles were set by applyPinnedHostSize. */
|
|
94
|
+
private _hostSizePinned;
|
|
95
|
+
private _resizeController;
|
|
96
|
+
firstUpdated(changed: PropertyValues): void;
|
|
97
|
+
updated(changed: PropertyValues): void;
|
|
85
98
|
private get _needleTransform();
|
|
86
99
|
getAngle(value: number): number;
|
|
87
100
|
get barColor(): "var(--instrument-regular-secondary-color)" | "var(--instrument-enhanced-secondary-color)" | "var(--instrument-frame-tertiary-color)" | "var(--instrument-regular-tertiary-color)" | "var(--instrument-enhanced-tertiary-color)";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rudder.d.ts","sourceRoot":"","sources":["../../../src/navigation-instruments/rudder/rudder.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,UAAU,EAAa,OAAO,EAAM,MAAM,KAAK,CAAC;
|
|
1
|
+
{"version":3,"file":"rudder.d.ts","sourceRoot":"","sources":["../../../src/navigation-instruments/rudder/rudder.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,UAAU,EAAE,cAAc,EAAa,OAAO,EAAM,MAAM,KAAK,CAAC;AAGxE,OAAO,mBAAmB,CAAC;AAC3B,OAAO,EAAW,aAAa,EAAe,MAAM,sBAAsB,CAAC;AAE3E,OAAO,EAAC,eAAe,EAAE,QAAQ,EAAC,MAAM,aAAa,CAAC;AAEtD,OAAO,EAAc,WAAW,EAAiB,MAAM,oBAAoB,CAAC;AAW5E,oBAAY,gBAAgB;IAC1B,GAAG,QAAQ;IACX,MAAM,WAAW;CAClB;;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2DG;AACH,qBACa,SAAU,SAAQ,cAAyB;IAC5B,KAAK,SAAK;IACV,OAAO,EAAE,gBAAgB,CAAwB;IACjD,QAAQ,SAAM;IACb,UAAU,EAAE,OAAO,CAAS;IACvD,mDAAmD;IACxB,eAAe,EAAE,OAAO,CAAS;IAClC,KAAK,EAAE,eAAe,CAA0B;IAChD,QAAQ,EAAE,QAAQ,CAAoB;IACtC,aAAa,EAAE,aAAa,CAC9B;IACmB,OAAO,EAAE,WAAW,EAAE,CAAM;IAC5C,YAAY,EAAE,OAAO,CAAS;IACzD;;;;;;OAMG;IAEH,YAAY,EAAE,MAAM,GAAG,SAAS,CAAC;IAEjC,OAAO,CAAC,aAAa,CAAK;IAC1B,OAAO,CAAC,MAAM,CAA0B;IAExC,oEAAoE;IACpE,OAAO,CAAC,eAAe,CAAS;IAEhC,OAAO,CAAC,iBAAiB,CAAkC;IAElD,YAAY,CAAC,OAAO,EAAE,cAAc,GAAG,IAAI;IAK3C,OAAO,CAAC,OAAO,EAAE,cAAc,GAAG,IAAI;IAS/C,OAAO,KAAK,gBAAgB,GAM3B;IAED,QAAQ,CAAC,KAAK,EAAE,MAAM;IAItB,IAAI,QAAQ,qOAsBX;IAED,YAAY;IA0BH,MAAM;IAmIf,OAAgB,MAAM,0BAkBpB;CACH;AAED,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,YAAY,EAAE,SAAS,CAAC;KACzB;CACF"}
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { LitElement, nothing, svg, html, css } from "lit";
|
|
2
2
|
import { property } from "lit/decorators.js";
|
|
3
|
-
import {
|
|
3
|
+
import { ResizeController } from "@lit-labs/observers/resize-controller.js";
|
|
4
|
+
import { innerRingRadiusFor, WatchCircleType } from "../watch/watch.js";
|
|
4
5
|
import { TickmarkStyle, TickmarkType } from "../watch/tickmark.js";
|
|
5
6
|
import { InstrumentState, Priority } from "../types.js";
|
|
6
7
|
import { SetpointMixin } from "../../svghelpers/setpoint-mixin.js";
|
|
7
8
|
import { AdviceState } from "../watch/advice.js";
|
|
8
9
|
import { customElement } from "../../decorator.js";
|
|
9
|
-
import {
|
|
10
|
+
import { observeInnerBox, applyPinnedHostSize, computeRadialFrame, measureContainerPx, estimateLabelWidthPx } from "../../svghelpers/radial-frame.js";
|
|
10
11
|
var __defProp = Object.defineProperty;
|
|
11
12
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
12
13
|
var __decorateClass = (decorators, target, key, kind) => {
|
|
@@ -36,6 +37,20 @@ let ObcRudder = class extends SetpointMixin(LitElement) {
|
|
|
36
37
|
this.advices = [];
|
|
37
38
|
this.zoomToFitArc = false;
|
|
38
39
|
this._radiusOffset = 0;
|
|
40
|
+
this._hostSizePinned = false;
|
|
41
|
+
this._resizeController = new ResizeController(this, {});
|
|
42
|
+
}
|
|
43
|
+
firstUpdated(changed) {
|
|
44
|
+
super.firstUpdated(changed);
|
|
45
|
+
observeInnerBox(this._resizeController, this.renderRoot);
|
|
46
|
+
}
|
|
47
|
+
updated(changed) {
|
|
48
|
+
super.updated(changed);
|
|
49
|
+
this._hostSizePinned = applyPinnedHostSize(
|
|
50
|
+
this,
|
|
51
|
+
this._frame,
|
|
52
|
+
this._hostSizePinned
|
|
53
|
+
);
|
|
39
54
|
}
|
|
40
55
|
get _needleTransform() {
|
|
41
56
|
const rOff = this._radiusOffset;
|
|
@@ -150,32 +165,25 @@ let ObcRudder = class extends SetpointMixin(LitElement) {
|
|
|
150
165
|
state
|
|
151
166
|
};
|
|
152
167
|
});
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
} else {
|
|
168
|
-
overlayViewBox = "-224 -44.8 448 268.8";
|
|
169
|
-
this._radiusOffset = 0;
|
|
170
|
-
this._arcFrame = void 0;
|
|
171
|
-
}
|
|
168
|
+
const frame = computeRadialFrame({
|
|
169
|
+
basePadding: 48,
|
|
170
|
+
labelWidthPx: this.tickmarksInside ? 0 : estimateLabelWidthPx(tickmarks.map((t) => t.text)),
|
|
171
|
+
clips: this.zoomToFitArc ? void 0 : { top: 40, bottom: 0, left: 0, right: 0 },
|
|
172
|
+
containerPx: measureContainerPx(this),
|
|
173
|
+
faceDiameter: this.faceDiameter,
|
|
174
|
+
zoomToFitArc: this.zoomToFitArc,
|
|
175
|
+
areas,
|
|
176
|
+
innerRadius: innerRingRadiusFor(WatchCircleType.double)
|
|
177
|
+
});
|
|
178
|
+
this._radiusOffset = frame.radiusOffset;
|
|
179
|
+
this._frame = frame;
|
|
180
|
+
const shownTickmarks = frame.labelsHidden ? tickmarks.map((t) => ({ ...t, text: void 0 })) : tickmarks;
|
|
181
|
+
const overlayViewBox = frame.viewBox;
|
|
172
182
|
return html`
|
|
173
183
|
<div class="container">
|
|
174
184
|
<obc-watch
|
|
175
185
|
.touching=${this.touching}
|
|
176
|
-
.
|
|
177
|
-
.zoomToFitArc=${this.zoomToFitArc}
|
|
178
|
-
.arcFrame=${this._arcFrame}
|
|
186
|
+
.arcFrame=${frame}
|
|
179
187
|
.areas=${areas}
|
|
180
188
|
.angleSetpoint=${setpointAngle}
|
|
181
189
|
.newAngleSetpoint=${this.newSetpoint !== void 0 ? 180 - this.newSetpoint : void 0}
|
|
@@ -183,8 +191,7 @@ let ObcRudder = class extends SetpointMixin(LitElement) {
|
|
|
183
191
|
.angleSetpointAtZeroDeadband=${this.setpointAtZeroDeadband}
|
|
184
192
|
.setpointOverride=${this.setpointOverride}
|
|
185
193
|
.animateSetpoint=${this.animateSetpoint}
|
|
186
|
-
.
|
|
187
|
-
.tickmarks=${tickmarks}
|
|
194
|
+
.tickmarks=${shownTickmarks}
|
|
188
195
|
.tickmarksInside=${this.tickmarksInside}
|
|
189
196
|
.tickmarkStyle=${this.tickmarkStyle}
|
|
190
197
|
.watchCircleType=${WatchCircleType.double}
|
|
@@ -247,6 +254,9 @@ __decorateClass([
|
|
|
247
254
|
__decorateClass([
|
|
248
255
|
property({ type: Boolean })
|
|
249
256
|
], ObcRudder.prototype, "zoomToFitArc", 2);
|
|
257
|
+
__decorateClass([
|
|
258
|
+
property({ type: Number, attribute: "face-diameter" })
|
|
259
|
+
], ObcRudder.prototype, "faceDiameter", 2);
|
|
250
260
|
ObcRudder = __decorateClass([
|
|
251
261
|
customElement("obc-rudder")
|
|
252
262
|
], ObcRudder);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rudder.js","sources":["../../../src/navigation-instruments/rudder/rudder.ts"],"sourcesContent":["import {LitElement, css, html, nothing, svg} from 'lit';\nimport {property} from 'lit/decorators.js';\nimport '../watch/watch.js';\nimport {Tickmark, TickmarkStyle, TickmarkType} from '../watch/tickmark.js';\nimport {\n OUTER_RING_RADIUS,\n WatchCircleType,\n innerRingRadiusFor,\n} from '../watch/watch.js';\nimport {InstrumentState, Priority} from '../types.js';\nimport {SetpointMixin} from '../../svghelpers/setpoint-mixin.js';\nimport {AdviceState, AngleAdvice, AngleAdviceRaw} from '../watch/advice.js';\nimport {customElement} from '../../decorator.js';\nimport {\n computeZoomToFitArcFrame,\n type ZoomToFitArcFrame,\n} from '../../svghelpers/arc-frame.js';\n\nexport enum ObcRudderVariant {\n Bar = 'bar',\n Needle = 'needle',\n}\n\n/**\n * `<obc-rudder>` — Half-circle rudder angle indicator.\n *\n * `ObcRudder` renders a semicircular gauge (40% top-clipped) that displays\n * the current rudder angle with a configurable bar or needle variant. The\n * gauge maps rudder angles to the lower arc of an `<obc-watch>` and overlays\n * a domain-specific needle when the `needle` variant is selected. It inherits\n * a full setpoint property bundle from {@link SetpointMixin}, including\n * auto at-setpoint detection, dual-marker adjustment preview, and deadband\n * tuning.\n *\n * ## Features\n *\n * - **Two display variants**: `bar` (filled arc from zero, default) and\n * `needle` (rotating pointer with silhouette stroke) via the `variant`\n * property.\n * - **Symmetric range**: The gauge spans ±`maxAngle` around the 180° center\n * (zero position at bottom).\n * - **State-aware colors**: Bar and needle colors adapt to the current\n * `InstrumentState` (active, loading, off) and `Priority` (enhanced, regular).\n * - **Setpoint via mixin**: `setpoint`, `newSetpoint`, `touching`,\n * `autoAtSetpointDeadband`, `setpointOverride`, and all other setpoint\n * properties are provided by `SetpointMixin` and forwarded to `<obc-watch>`.\n * - **Advice zones**: Pass an array of `AngleAdvice` objects to render\n * caution/alert arcs; triggered state is derived from whether the setpoint\n * falls inside the advice range.\n *\n * ## Usage Guidelines\n *\n * - Set `maxAngle` to define the symmetric ± range (default: 90°).\n * - Use `priority` to switch between regular and enhanced color palettes\n * (default: `Priority.regular`).\n * - Use `state` to control the instrument color palette.\n * - Enable `showLabels` to show numeric angle labels at tickmarks.\n * - Enable `tickmarksInside` to render tickmarks inside the ring.\n * - Choose `variant` to switch between bar and needle display.\n *\n * ## Best Practices\n *\n * - Prefer `SetpointMixin` properties (`setpoint`, `touching`, etc.) over\n * any legacy aliases — the mixin is the single source of truth.\n * - The top 40% is always clipped; overlay SVGs use the matching clipped\n * viewBox (`-224 -44.8 448 268.8`) for layer alignment.\n *\n * ## Example\n *\n * ```html\n * <obc-rudder\n * angle=\"12\"\n * maxAngle=\"45\"\n * variant=\"needle\"\n * state=\"in-command\"\n * showLabels\n * setpoint=\"15\"\n * ></obc-rudder>\n * ```\n *\n * @element obc-rudder\n * @stable\n */\n@customElement('obc-rudder')\nexport class ObcRudder extends SetpointMixin(LitElement) {\n @property({type: Number}) angle = 0;\n @property({type: String}) variant: ObcRudderVariant = ObcRudderVariant.Bar;\n @property({type: Number}) maxAngle = 90;\n @property({type: Boolean}) showLabels: boolean = false;\n /** Whether to render tickmarks inside the ring. */\n @property({type: Boolean}) tickmarksInside: boolean = false;\n @property({type: String}) state: InstrumentState = InstrumentState.active;\n @property({type: String}) priority: Priority = Priority.regular;\n @property({type: String}) tickmarkStyle: TickmarkStyle =\n TickmarkStyle.regular;\n @property({type: Array, attribute: false}) advices: AngleAdvice[] = [];\n @property({type: Boolean}) zoomToFitArc: boolean = false;\n\n private _radiusOffset = 0;\n private _arcFrame: ZoomToFitArcFrame | undefined;\n\n private get _needleTransform(): string {\n const rOff = this._radiusOffset;\n if (rOff > 0) {\n return `translate(-256, -256) rotate(${-this.angle} 256 256) translate(0, ${rOff})`;\n }\n return `translate(-256, -256) rotate(${-this.angle} 256 256)`;\n }\n\n getAngle(value: number) {\n return 180 - value;\n }\n\n get barColor() {\n if (this.variant === ObcRudderVariant.Needle) {\n if (\n this.state === InstrumentState.loading ||\n this.state === InstrumentState.off\n ) {\n return 'var(--instrument-frame-tertiary-color)';\n }\n return this.priority === Priority.enhanced\n ? 'var(--instrument-enhanced-tertiary-color)'\n : 'var(--instrument-regular-tertiary-color)';\n } else {\n if (\n this.state === InstrumentState.loading ||\n this.state === InstrumentState.off\n ) {\n return 'var(--instrument-frame-tertiary-color)';\n }\n return this.priority === Priority.enhanced\n ? 'var(--instrument-enhanced-secondary-color)'\n : 'var(--instrument-regular-secondary-color)';\n }\n }\n\n renderNeedle() {\n if (this.variant === ObcRudderVariant.Bar) {\n return nothing;\n }\n let color: string;\n if (\n this.state === InstrumentState.loading ||\n this.state === InstrumentState.off\n ) {\n color = 'var(--instrument-frame-tertiary-color)';\n } else {\n color =\n this.priority === Priority.enhanced\n ? 'var(--instrument-enhanced-secondary-color)'\n : 'var(--instrument-regular-secondary-color)';\n }\n return svg`\n <path\n transform=\"${this._needleTransform}\"\n d=\"M260.462 411.447C259.81 416.73 251.933 416.645 251.514 411.191L239.826 259.24C239.618 258.192 239.508 257.109 239.508 256C239.508 255.764 239.514 255.528 239.524 255.294L239.503 255.039L239.462 254.5H239.576C240.334 246.09 247.401 239.5 256.008 239.5C264.615 239.5 271.681 246.09 272.439 254.5H272.542L272.5 255.039L272.488 255.196C272.501 255.462 272.508 255.731 272.508 256C272.508 257.144 272.391 258.261 272.169 259.339L260.487 411.191L260.462 411.447Z\"\n fill=\"${color}\"\n stroke=\"var(--border-silhouette-color)\"\n />\n `;\n }\n\n override render() {\n const maxAngle = Math.max(2, this.maxAngle);\n const areas = [\n {\n startAngle: 180 - maxAngle,\n endAngle: 180 + maxAngle,\n roundInsideCut: true,\n roundOutsideCut: true,\n },\n ];\n\n const barAreas = [\n {\n startAngle: this.getAngle(0),\n endAngle: this.getAngle(this.angle),\n fillColor: this.barColor,\n },\n ];\n\n const setpointAngle =\n this.setpoint !== undefined ? 180 - this.setpoint : undefined;\n\n const tickmarks: Tickmark[] = [\n {\n angle: 180,\n type: TickmarkType.primary,\n text: this.showLabels ? '0' : undefined,\n },\n {\n angle: 180,\n type: TickmarkType.zeroLineThick,\n color: this.barColor,\n },\n {\n angle: 180 - maxAngle,\n type: TickmarkType.secondary,\n text: this.showLabels ? maxAngle.toFixed(0) : undefined,\n },\n {\n angle: 180 + maxAngle,\n type: TickmarkType.secondary,\n text: this.showLabels ? (-maxAngle).toFixed(0) : undefined,\n },\n ];\n\n let helpAngle: null | number = null;\n if (maxAngle > 70) {\n helpAngle = 45;\n } else if (maxAngle > 50) {\n helpAngle = 30;\n } else if (maxAngle > 40) {\n helpAngle = 22.5;\n }\n\n if (helpAngle !== null) {\n tickmarks.push({angle: 180 - helpAngle, type: TickmarkType.primary});\n tickmarks.push({angle: 180 + helpAngle, type: TickmarkType.primary});\n }\n\n const advices = this.advices.map<AngleAdviceRaw>((adv): AngleAdviceRaw => {\n const startAngle = 180 - adv.maxAngle;\n const endAngle = 180 - adv.minAngle;\n const isInRange =\n this.setpoint !== undefined &&\n this.setpoint >= adv.minAngle &&\n this.setpoint <= adv.maxAngle;\n let state;\n if (isInRange) {\n state = AdviceState.triggered;\n } else if (adv.hinted) {\n state = AdviceState.hinted;\n } else {\n state = AdviceState.regular;\n }\n return {\n minAngle: startAngle,\n maxAngle: endAngle,\n type: adv.type,\n state: state,\n };\n });\n\n let overlayViewBox: string;\n if (this.zoomToFitArc) {\n const ext = 48;\n const targetSize = (176 + ext) * 2;\n const frame = computeZoomToFitArcFrame({\n areas,\n outerRadius: OUTER_RING_RADIUS,\n innerRadius: innerRingRadiusFor(WatchCircleType.double),\n extension: ext,\n targetSize,\n });\n overlayViewBox = frame.viewBox;\n this._radiusOffset = frame.radiusOffset;\n this._arcFrame = frame;\n } else {\n overlayViewBox = '-224 -44.8 448 268.8';\n this._radiusOffset = 0;\n this._arcFrame = undefined;\n }\n\n return html`\n <div class=\"container\">\n <obc-watch\n .touching=${this.touching}\n .clipTop=${this.zoomToFitArc ? 0 : 40}\n .zoomToFitArc=${this.zoomToFitArc}\n .arcFrame=${this._arcFrame}\n .areas=${areas}\n .angleSetpoint=${setpointAngle}\n .newAngleSetpoint=${this.newSetpoint !== undefined\n ? 180 - this.newSetpoint\n : undefined}\n .atAngleSetpoint=${this.computeAtSetpoint(this.angle)}\n .angleSetpointAtZeroDeadband=${this.setpointAtZeroDeadband}\n .setpointOverride=${this.setpointOverride}\n .animateSetpoint=${this.animateSetpoint}\n .padding=${48}\n .tickmarks=${tickmarks}\n .tickmarksInside=${this.tickmarksInside}\n .tickmarkStyle=${this.tickmarkStyle}\n .watchCircleType=${WatchCircleType.double}\n .barAreas=${barAreas}\n .state=${this.state}\n .priority=${this.priority}\n .advices=${advices}\n ></obc-watch>\n <svg viewBox=\"${overlayViewBox}\">${this.renderNeedle()}</svg>\n </div>\n `;\n }\n\n static override styles = css`\n * {\n box-sizing: border-box;\n }\n\n .container {\n position: relative;\n width: 100%;\n height: 100%;\n }\n\n .container > * {\n position: absolute;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n }\n `;\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'obc-rudder': ObcRudder;\n }\n}\n"],"names":["ObcRudderVariant"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"rudder.js","sources":["../../../src/navigation-instruments/rudder/rudder.ts"],"sourcesContent":["import {LitElement, PropertyValues, css, html, nothing, svg} from 'lit';\nimport {property} from 'lit/decorators.js';\nimport {ResizeController} from '@lit-labs/observers/resize-controller.js';\nimport '../watch/watch.js';\nimport {Tickmark, TickmarkStyle, TickmarkType} from '../watch/tickmark.js';\nimport {WatchCircleType, innerRingRadiusFor} from '../watch/watch.js';\nimport {InstrumentState, Priority} from '../types.js';\nimport {SetpointMixin} from '../../svghelpers/setpoint-mixin.js';\nimport {AdviceState, AngleAdvice, AngleAdviceRaw} from '../watch/advice.js';\nimport {customElement} from '../../decorator.js';\nimport {\n applyPinnedHostSize,\n computeRadialFrame,\n estimateLabelWidthPx,\n measureContainerPx,\n observeInnerBox,\n type RadialFrame,\n} from '../../svghelpers/radial-frame.js';\n\nexport enum ObcRudderVariant {\n Bar = 'bar',\n Needle = 'needle',\n}\n\n/**\n * `<obc-rudder>` — Half-circle rudder angle indicator.\n *\n * `ObcRudder` renders a semicircular gauge (40% top-clipped) that displays\n * the current rudder angle with a configurable bar or needle variant. The\n * gauge maps rudder angles to the lower arc of an `<obc-watch>` and overlays\n * a domain-specific needle when the `needle` variant is selected. It inherits\n * a full setpoint property bundle from {@link SetpointMixin}, including\n * auto at-setpoint detection, dual-marker adjustment preview, and deadband\n * tuning.\n *\n * ## Features\n *\n * - **Two display variants**: `bar` (filled arc from zero, default) and\n * `needle` (rotating pointer with silhouette stroke) via the `variant`\n * property.\n * - **Symmetric range**: The gauge spans ±`maxAngle` around the 180° center\n * (zero position at bottom).\n * - **State-aware colors**: Bar and needle colors adapt to the current\n * `InstrumentState` (active, loading, off) and `Priority` (enhanced, regular).\n * - **Setpoint via mixin**: `setpoint`, `newSetpoint`, `touching`,\n * `autoAtSetpointDeadband`, `setpointOverride`, and all other setpoint\n * properties are provided by `SetpointMixin` and forwarded to `<obc-watch>`.\n * - **Advice zones**: Pass an array of `AngleAdvice` objects to render\n * caution/alert arcs; triggered state is derived from whether the setpoint\n * falls inside the advice range.\n *\n * ## Usage Guidelines\n *\n * - Set `maxAngle` to define the symmetric ± range (default: 90°).\n * - Use `priority` to switch between regular and enhanced color palettes\n * (default: `Priority.regular`).\n * - Use `state` to control the instrument color palette.\n * - Enable `showLabels` to show numeric angle labels at tickmarks.\n * - Enable `tickmarksInside` to render tickmarks inside the ring.\n * - Choose `variant` to switch between bar and needle display.\n *\n * ## Best Practices\n *\n * - Prefer `SetpointMixin` properties (`setpoint`, `touching`, etc.) over\n * any legacy aliases — the mixin is the single source of truth.\n * - The top 40% is always clipped; overlay SVGs use the matching clipped\n * viewBox (`-224 -44.8 448 268.8`) for layer alignment.\n *\n * ## Example\n *\n * ```html\n * <obc-rudder\n * angle=\"12\"\n * maxAngle=\"45\"\n * variant=\"needle\"\n * state=\"in-command\"\n * showLabels\n * setpoint=\"15\"\n * ></obc-rudder>\n * ```\n *\n * @element obc-rudder\n * @stable\n */\n@customElement('obc-rudder')\nexport class ObcRudder extends SetpointMixin(LitElement) {\n @property({type: Number}) angle = 0;\n @property({type: String}) variant: ObcRudderVariant = ObcRudderVariant.Bar;\n @property({type: Number}) maxAngle = 90;\n @property({type: Boolean}) showLabels: boolean = false;\n /** Whether to render tickmarks inside the ring. */\n @property({type: Boolean}) tickmarksInside: boolean = false;\n @property({type: String}) state: InstrumentState = InstrumentState.active;\n @property({type: String}) priority: Priority = Priority.regular;\n @property({type: String}) tickmarkStyle: TickmarkStyle =\n TickmarkStyle.regular;\n @property({type: Array, attribute: false}) advices: AngleAdvice[] = [];\n @property({type: Boolean}) zoomToFitArc: boolean = false;\n /**\n * Outer-ring diameter in CSS pixels. When set, the instrument renders at a\n * fixed intrinsic size derived from the ring, arc shape and label reserve —\n * so instruments sharing the same value have identical ring circumference\n * regardless of label width or arc extent (like obc-donut-chart's\n * fixedHeight). When unset (default), the instrument fills its container.\n */\n @property({type: Number, attribute: 'face-diameter'})\n faceDiameter: number | undefined;\n\n private _radiusOffset = 0;\n private _frame: RadialFrame | undefined;\n\n /** Whether the host size styles were set by applyPinnedHostSize. */\n private _hostSizePinned = false;\n\n private _resizeController = new ResizeController(this, {});\n\n override firstUpdated(changed: PropertyValues): void {\n super.firstUpdated(changed);\n observeInnerBox(this._resizeController, this.renderRoot);\n }\n\n override updated(changed: PropertyValues): void {\n super.updated(changed);\n this._hostSizePinned = applyPinnedHostSize(\n this,\n this._frame,\n this._hostSizePinned\n );\n }\n\n private get _needleTransform(): string {\n const rOff = this._radiusOffset;\n if (rOff > 0) {\n return `translate(-256, -256) rotate(${-this.angle} 256 256) translate(0, ${rOff})`;\n }\n return `translate(-256, -256) rotate(${-this.angle} 256 256)`;\n }\n\n getAngle(value: number) {\n return 180 - value;\n }\n\n get barColor() {\n if (this.variant === ObcRudderVariant.Needle) {\n if (\n this.state === InstrumentState.loading ||\n this.state === InstrumentState.off\n ) {\n return 'var(--instrument-frame-tertiary-color)';\n }\n return this.priority === Priority.enhanced\n ? 'var(--instrument-enhanced-tertiary-color)'\n : 'var(--instrument-regular-tertiary-color)';\n } else {\n if (\n this.state === InstrumentState.loading ||\n this.state === InstrumentState.off\n ) {\n return 'var(--instrument-frame-tertiary-color)';\n }\n return this.priority === Priority.enhanced\n ? 'var(--instrument-enhanced-secondary-color)'\n : 'var(--instrument-regular-secondary-color)';\n }\n }\n\n renderNeedle() {\n if (this.variant === ObcRudderVariant.Bar) {\n return nothing;\n }\n let color: string;\n if (\n this.state === InstrumentState.loading ||\n this.state === InstrumentState.off\n ) {\n color = 'var(--instrument-frame-tertiary-color)';\n } else {\n color =\n this.priority === Priority.enhanced\n ? 'var(--instrument-enhanced-secondary-color)'\n : 'var(--instrument-regular-secondary-color)';\n }\n return svg`\n <path\n transform=\"${this._needleTransform}\"\n d=\"M260.462 411.447C259.81 416.73 251.933 416.645 251.514 411.191L239.826 259.24C239.618 258.192 239.508 257.109 239.508 256C239.508 255.764 239.514 255.528 239.524 255.294L239.503 255.039L239.462 254.5H239.576C240.334 246.09 247.401 239.5 256.008 239.5C264.615 239.5 271.681 246.09 272.439 254.5H272.542L272.5 255.039L272.488 255.196C272.501 255.462 272.508 255.731 272.508 256C272.508 257.144 272.391 258.261 272.169 259.339L260.487 411.191L260.462 411.447Z\"\n fill=\"${color}\"\n stroke=\"var(--border-silhouette-color)\"\n />\n `;\n }\n\n override render() {\n const maxAngle = Math.max(2, this.maxAngle);\n const areas = [\n {\n startAngle: 180 - maxAngle,\n endAngle: 180 + maxAngle,\n roundInsideCut: true,\n roundOutsideCut: true,\n },\n ];\n\n const barAreas = [\n {\n startAngle: this.getAngle(0),\n endAngle: this.getAngle(this.angle),\n fillColor: this.barColor,\n },\n ];\n\n const setpointAngle =\n this.setpoint !== undefined ? 180 - this.setpoint : undefined;\n\n const tickmarks: Tickmark[] = [\n {\n angle: 180,\n type: TickmarkType.primary,\n text: this.showLabels ? '0' : undefined,\n },\n {\n angle: 180,\n type: TickmarkType.zeroLineThick,\n color: this.barColor,\n },\n {\n angle: 180 - maxAngle,\n type: TickmarkType.secondary,\n text: this.showLabels ? maxAngle.toFixed(0) : undefined,\n },\n {\n angle: 180 + maxAngle,\n type: TickmarkType.secondary,\n text: this.showLabels ? (-maxAngle).toFixed(0) : undefined,\n },\n ];\n\n let helpAngle: null | number = null;\n if (maxAngle > 70) {\n helpAngle = 45;\n } else if (maxAngle > 50) {\n helpAngle = 30;\n } else if (maxAngle > 40) {\n helpAngle = 22.5;\n }\n\n if (helpAngle !== null) {\n tickmarks.push({angle: 180 - helpAngle, type: TickmarkType.primary});\n tickmarks.push({angle: 180 + helpAngle, type: TickmarkType.primary});\n }\n\n const advices = this.advices.map<AngleAdviceRaw>((adv): AngleAdviceRaw => {\n const startAngle = 180 - adv.maxAngle;\n const endAngle = 180 - adv.minAngle;\n const isInRange =\n this.setpoint !== undefined &&\n this.setpoint >= adv.minAngle &&\n this.setpoint <= adv.maxAngle;\n let state;\n if (isInRange) {\n state = AdviceState.triggered;\n } else if (adv.hinted) {\n state = AdviceState.hinted;\n } else {\n state = AdviceState.regular;\n }\n return {\n minAngle: startAngle,\n maxAngle: endAngle,\n type: adv.type,\n state: state,\n };\n });\n\n const frame = computeRadialFrame({\n basePadding: 48,\n labelWidthPx: this.tickmarksInside\n ? 0\n : estimateLabelWidthPx(tickmarks.map((t) => t.text)),\n clips: this.zoomToFitArc\n ? undefined\n : {top: 40, bottom: 0, left: 0, right: 0},\n containerPx: measureContainerPx(this),\n faceDiameter: this.faceDiameter,\n zoomToFitArc: this.zoomToFitArc,\n areas,\n innerRadius: innerRingRadiusFor(WatchCircleType.double),\n });\n this._radiusOffset = frame.radiusOffset;\n this._frame = frame;\n const shownTickmarks = frame.labelsHidden\n ? tickmarks.map((t) => ({...t, text: undefined}))\n : tickmarks;\n const overlayViewBox = frame.viewBox;\n\n return html`\n <div class=\"container\">\n <obc-watch\n .touching=${this.touching}\n .arcFrame=${frame}\n .areas=${areas}\n .angleSetpoint=${setpointAngle}\n .newAngleSetpoint=${this.newSetpoint !== undefined\n ? 180 - this.newSetpoint\n : undefined}\n .atAngleSetpoint=${this.computeAtSetpoint(this.angle)}\n .angleSetpointAtZeroDeadband=${this.setpointAtZeroDeadband}\n .setpointOverride=${this.setpointOverride}\n .animateSetpoint=${this.animateSetpoint}\n .tickmarks=${shownTickmarks}\n .tickmarksInside=${this.tickmarksInside}\n .tickmarkStyle=${this.tickmarkStyle}\n .watchCircleType=${WatchCircleType.double}\n .barAreas=${barAreas}\n .state=${this.state}\n .priority=${this.priority}\n .advices=${advices}\n ></obc-watch>\n <svg viewBox=\"${overlayViewBox}\">${this.renderNeedle()}</svg>\n </div>\n `;\n }\n\n static override styles = css`\n * {\n box-sizing: border-box;\n }\n\n .container {\n position: relative;\n width: 100%;\n height: 100%;\n }\n\n .container > * {\n position: absolute;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n }\n `;\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'obc-rudder': ObcRudder;\n }\n}\n"],"names":["ObcRudderVariant"],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { LitElement } from 'lit';
|
|
1
|
+
import { LitElement, PropertyValues } from 'lit';
|
|
2
2
|
import { Tickmark, TickmarkStyle } from '../watch/tickmark.js';
|
|
3
3
|
import { AdviceType, AngleAdviceRaw } from '../watch/advice.js';
|
|
4
4
|
import { Priority } from '../types.js';
|
|
@@ -102,6 +102,20 @@ export declare class ObcSpeedGauge extends ObcSpeedGauge_base {
|
|
|
102
102
|
unit: string;
|
|
103
103
|
/** Number of fraction digits shown in the readout. Default `1`. */
|
|
104
104
|
fractionDigits: number;
|
|
105
|
+
/**
|
|
106
|
+
* Outer-ring diameter in CSS pixels. When set, the instrument renders at a
|
|
107
|
+
* fixed intrinsic size derived from the ring, arc shape and label reserve —
|
|
108
|
+
* so instruments sharing the same value have identical ring circumference
|
|
109
|
+
* regardless of label width or arc extent (like obc-donut-chart's
|
|
110
|
+
* fixedHeight). When unset (default), the instrument fills its container.
|
|
111
|
+
*/
|
|
112
|
+
faceDiameter: number | undefined;
|
|
113
|
+
private _frame;
|
|
114
|
+
/** Whether the host size styles were set by applyPinnedHostSize. */
|
|
115
|
+
private _hostSizePinned;
|
|
116
|
+
private _resizeController;
|
|
117
|
+
firstUpdated(changed: PropertyValues): void;
|
|
118
|
+
updated(changed: PropertyValues): void;
|
|
105
119
|
getAngle(v: number): number;
|
|
106
120
|
get minAngle(): number;
|
|
107
121
|
maxAngle: number;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"speed-gauge.d.ts","sourceRoot":"","sources":["../../../src/navigation-instruments/speed-gauge/speed-gauge.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,UAAU,EAA0B,MAAM,KAAK,CAAC;
|
|
1
|
+
{"version":3,"file":"speed-gauge.d.ts","sourceRoot":"","sources":["../../../src/navigation-instruments/speed-gauge/speed-gauge.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,UAAU,EAAE,cAAc,EAA0B,MAAM,KAAK,CAAC;AAWxE,OAAO,EAAC,QAAQ,EAAE,aAAa,EAAe,MAAM,sBAAsB,CAAC;AAE3E,OAAO,EAAC,UAAU,EAAE,cAAc,EAAc,MAAM,oBAAoB,CAAC;AAE3E,OAAO,EAAC,QAAQ,EAAC,MAAM,aAAa,CAAC;AAKrC,oBAAY,uBAAuB;IACjC,IAAI,SAAS;IACb,GAAG,QAAQ;CACZ;AAED,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,UAAU,CAAC;IACjB,MAAM,EAAE,OAAO,CAAC;CACjB;;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6DG;AACH,qBACa,aAAc,SAAQ,kBAAyB;IAChC,KAAK,SAAK;IACV,QAAQ,SAAO;IACf,QAAQ,SAAK;IACZ,UAAU,EAAE,OAAO,CAAS;IACvD,mDAAmD;IACxB,eAAe,EAAE,OAAO,CAAS;IAC5D;;;OAGG;IACuB,gBAAgB,EAAE,MAAM,GAAG,SAAS,CAAM;IAC1C,QAAQ,EAAE,QAAQ,CAAoB;IACtC,UAAU,EAAE,uBAAuB,CAC9B;IACY,YAAY,EAAE,WAAW,EAAE,CAAM;IAClD,aAAa,EAAE,aAAa,CAC9B;IACxB;;;OAGG;IACwB,UAAU,EAAE,OAAO,CAAS;IACvD,oCAAoC;IACV,KAAK,SAAS;IACxC,kCAAkC;IACR,IAAI,SAAQ;IACtC,mEAAmE;IACzC,cAAc,SAAK;IAC7C;;;;;;OAMG;IAEH,YAAY,EAAE,MAAM,GAAG,SAAS,CAAC;IAEjC,OAAO,CAAC,MAAM,CAA0B;IAExC,oEAAoE;IACpE,OAAO,CAAC,eAAe,CAAS;IAEhC,OAAO,CAAC,iBAAiB,CAAkC;IAElD,YAAY,CAAC,OAAO,EAAE,cAAc,GAAG,IAAI;IAK3C,OAAO,CAAC,OAAO,EAAE,cAAc,GAAG,IAAI;IAS/C,QAAQ,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM;IAI3B,IAAI,QAAQ,IAAI,MAAM,CAErB;IAED,QAAQ,SAAY;IAEX,MAAM;IA6Ef,IAAI,MAAM,yCAkBT;IAED,IAAI,SAAS,IAAI,QAAQ,EAAE,CA+C1B;IAED,IAAI,QAAQ,IAAI,cAAc,EAAE,CAqB/B;IAED,OAAgB,MAAM,0BAmCpB;CACH;AAED,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,iBAAiB,EAAE,aAAa,CAAC;KAClC;CACF"}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { LitElement, nothing, html, svg, css } from "lit";
|
|
2
2
|
import { property } from "lit/decorators.js";
|
|
3
|
+
import { ResizeController } from "@lit-labs/observers/resize-controller.js";
|
|
4
|
+
import { observeInnerBox, applyPinnedHostSize, computeRadialFrame, measureContainerPx, estimateLabelWidthPx } from "../../svghelpers/radial-frame.js";
|
|
3
5
|
import { TickmarkStyle, TickmarkType } from "../watch/tickmark.js";
|
|
4
6
|
import { WatchCircleType } from "../watch/watch.js";
|
|
5
7
|
import { AdviceState } from "../watch/advice.js";
|
|
@@ -40,8 +42,22 @@ let ObcSpeedGauge = class extends SetpointMixin(LitElement) {
|
|
|
40
42
|
this.label = "STW";
|
|
41
43
|
this.unit = "KN";
|
|
42
44
|
this.fractionDigits = 1;
|
|
45
|
+
this._hostSizePinned = false;
|
|
46
|
+
this._resizeController = new ResizeController(this, {});
|
|
43
47
|
this.maxAngle = 180 - 45;
|
|
44
48
|
}
|
|
49
|
+
firstUpdated(changed) {
|
|
50
|
+
super.firstUpdated(changed);
|
|
51
|
+
observeInnerBox(this._resizeController, this.renderRoot);
|
|
52
|
+
}
|
|
53
|
+
updated(changed) {
|
|
54
|
+
super.updated(changed);
|
|
55
|
+
this._hostSizePinned = applyPinnedHostSize(
|
|
56
|
+
this,
|
|
57
|
+
this._frame,
|
|
58
|
+
this._hostSizePinned
|
|
59
|
+
);
|
|
60
|
+
}
|
|
45
61
|
getAngle(v) {
|
|
46
62
|
return v / this.maxSpeed * (180 + 45) - 90;
|
|
47
63
|
}
|
|
@@ -52,6 +68,15 @@ let ObcSpeedGauge = class extends SetpointMixin(LitElement) {
|
|
|
52
68
|
const barColor = this.priority === Priority.enhanced ? "var(--instrument-enhanced-tertiary-color)" : "var(--instrument-regular-tertiary-color)";
|
|
53
69
|
const setpointAngle = this.setpoint !== void 0 ? this.getAngle(this.setpoint) : void 0;
|
|
54
70
|
const maxDigits = 1;
|
|
71
|
+
const tickmarks = this.tickmarks;
|
|
72
|
+
const frame = computeRadialFrame({
|
|
73
|
+
basePadding: 48,
|
|
74
|
+
labelWidthPx: this.tickmarksInside ? 0 : estimateLabelWidthPx(tickmarks.map((t) => t.text)),
|
|
75
|
+
containerPx: measureContainerPx(this),
|
|
76
|
+
faceDiameter: this.faceDiameter
|
|
77
|
+
});
|
|
78
|
+
this._frame = frame;
|
|
79
|
+
const shownTickmarks = frame.labelsHidden ? tickmarks.map((t) => ({ ...t, text: void 0 })) : tickmarks;
|
|
55
80
|
return html`
|
|
56
81
|
<div class="container">
|
|
57
82
|
<obc-watch
|
|
@@ -62,8 +87,8 @@ let ObcSpeedGauge = class extends SetpointMixin(LitElement) {
|
|
|
62
87
|
.angleSetpointAtZeroDeadband=${this.setpointAtZeroDeadband}
|
|
63
88
|
.setpointOverride=${this.setpointOverride}
|
|
64
89
|
.animateSetpoint=${this.animateSetpoint}
|
|
65
|
-
.
|
|
66
|
-
.tickmarks=${
|
|
90
|
+
.arcFrame=${frame}
|
|
91
|
+
.tickmarks=${shownTickmarks}
|
|
67
92
|
.tickmarksInside=${this.tickmarksInside}
|
|
68
93
|
.tickmarkStyle=${this.tickmarkStyle}
|
|
69
94
|
.advices=${this._advices}
|
|
@@ -84,7 +109,7 @@ let ObcSpeedGauge = class extends SetpointMixin(LitElement) {
|
|
|
84
109
|
}
|
|
85
110
|
]}
|
|
86
111
|
></obc-watch>
|
|
87
|
-
<svg class="rudder" viewBox
|
|
112
|
+
<svg class="rudder" viewBox=${frame.viewBox}>${this.needle}</svg>
|
|
88
113
|
${this.hasReadout ? html`
|
|
89
114
|
${renderInstrumentReadout({
|
|
90
115
|
className: "speed-gauge-value",
|
|
@@ -253,6 +278,9 @@ __decorateClass([
|
|
|
253
278
|
__decorateClass([
|
|
254
279
|
property({ type: Number })
|
|
255
280
|
], ObcSpeedGauge.prototype, "fractionDigits", 2);
|
|
281
|
+
__decorateClass([
|
|
282
|
+
property({ type: Number, attribute: "face-diameter" })
|
|
283
|
+
], ObcSpeedGauge.prototype, "faceDiameter", 2);
|
|
256
284
|
ObcSpeedGauge = __decorateClass([
|
|
257
285
|
customElement("obc-speed-gauge")
|
|
258
286
|
], ObcSpeedGauge);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"speed-gauge.js","sources":["../../../src/navigation-instruments/speed-gauge/speed-gauge.ts"],"sourcesContent":["import {LitElement, css, html, nothing, svg} from 'lit';\nimport {property} from 'lit/decorators.js';\nimport {Tickmark, TickmarkStyle, TickmarkType} from '../watch/tickmark.js';\nimport {WatchCircleType} from '../watch/watch.js';\nimport {AdviceType, AngleAdviceRaw, AdviceState} from '../watch/advice.js';\nimport {SetpointMixin} from '../../svghelpers/setpoint-mixin.js';\nimport {Priority} from '../types.js';\nimport {renderInstrumentReadout} from '../readout/instrument-readout.js';\nimport {ReadoutDirection} from '../readout/readout.js';\nimport {customElement} from '../../decorator.js';\n\nexport enum ObcSpeedGaugeNeedleType {\n full = 'full',\n bar = 'bar',\n}\n\nexport interface SpeedAdvice {\n minSpeed: number;\n maxSpeed: number;\n type: AdviceType;\n hinted: boolean;\n}\n\n/**\n * `<obc-speed-gauge>` — Radial speed gauge with needle and optional readout.\n *\n * `ObcSpeedGauge` renders a 225° arc gauge (−90° to +135°) that displays\n * the current speed with a configurable full-length or bar needle. It layers\n * an `<obc-watch>` base with a needle SVG overlay and an optional numeric\n * readout field. It inherits a full setpoint property bundle from\n * {@link SetpointMixin}, including auto at-setpoint detection, dual-marker\n * adjustment preview, and deadband tuning.\n *\n * ## Features\n *\n * - **Two needle types**: `full` (pointer with center dot) and `bar`\n * (short indicator bar) via `needleType`.\n * - **Bipolar range support**: When `minSpeed < 0`, negative tickmarks are\n * rendered with `main` tick style.\n * - **Optional readout**: Enable `hasReadout` to display an\n * `<obc-readout>` with the current speed, unit (KN), and label (STW).\n * - **Setpoint via mixin**: `setpoint`, `newSetpoint`, `touching`,\n * `autoAtSetpointDeadband`, `setpointOverride`, and all other setpoint\n * properties are provided by `SetpointMixin`; the setpoint angle and\n * at-setpoint state are computed and forwarded to `<obc-watch>`.\n * - **Speed advice zones**: Pass an array of {@link SpeedAdvice} objects to\n * render caution/alert arcs; triggered state is derived from whether the\n * current speed falls inside the advice range.\n *\n * ## Usage Guidelines\n *\n * - Set `maxSpeed` (and optionally `minSpeed`) to define the gauge range.\n * - Use `priority` to switch between regular and enhanced color palettes\n * (default: `Priority.regular`).\n * - Provide `tickmarkInterval` to control tickmark spacing.\n * - Enable `showLabels` to show numeric labels at primary tickmarks.\n * - Enable `tickmarksInside` to render tickmarks inside the ring.\n * - Enable `hasReadout` to display the numeric value below the gauge.\n *\n * ## Best Practices\n *\n * - Prefer `SetpointMixin` properties (`setpoint`, `touching`, etc.) over\n * any legacy aliases — the mixin is the single source of truth.\n * - The needle overlay SVG uses viewBox `−224 −224 448 448` to align with\n * the `<obc-watch>` layer.\n *\n * ## Example\n *\n * ```html\n * <obc-speed-gauge\n * speed=\"12.5\"\n * maxSpeed=\"25\"\n * needleType=\"full\"\n * enhanced\n * showLabels\n * hasReadout\n * tickmarkInterval=\"5\"\n * setpoint=\"15\"\n * ></obc-speed-gauge>\n * ```\n *\n * @element obc-speed-gauge\n * @typedef {import('./speed-gauge.js').SpeedAdvice} SpeedAdvice\n * @stable\n */\n@customElement('obc-speed-gauge')\nexport class ObcSpeedGauge extends SetpointMixin(LitElement) {\n @property({type: Number}) speed = 0;\n @property({type: Number}) maxSpeed = 100;\n @property({type: Number}) minSpeed = 0;\n @property({type: Boolean}) showLabels: boolean = false;\n /** Whether to render tickmarks inside the ring. */\n @property({type: Boolean}) tickmarksInside: boolean = false;\n /**\n * Interval for tickmarks in speed units.\n * When undefined or <= 0, no tickmarks are shown (only the zero mark).\n */\n @property({type: Number}) tickmarkInterval: number | undefined = 20;\n @property({type: String}) priority: Priority = Priority.regular;\n @property({type: String}) needleType: ObcSpeedGaugeNeedleType =\n ObcSpeedGaugeNeedleType.full;\n @property({type: Array, attribute: false}) speedAdvices: SpeedAdvice[] = [];\n @property({type: String}) tickmarkStyle: TickmarkStyle =\n TickmarkStyle.regular;\n /**\n * When `true`, shows a centered `<obc-readout>` (label `STW`, unit `KN`)\n * below the gauge with the current speed. Default `false`.\n */\n @property({type: Boolean}) hasReadout: boolean = false;\n /** Readout label. Default `STW`. */\n @property({type: String}) label = 'STW';\n /** Readout unit. Default `KN`. */\n @property({type: String}) unit = 'KN';\n /** Number of fraction digits shown in the readout. Default `1`. */\n @property({type: Number}) fractionDigits = 1;\n\n getAngle(v: number): number {\n return (v / this.maxSpeed) * (180 + 45) - 90;\n }\n\n get minAngle(): number {\n return this.getAngle(this.minSpeed) - 360;\n }\n\n maxAngle = 180 - 45;\n\n override render() {\n const barColor =\n this.priority === Priority.enhanced\n ? 'var(--instrument-enhanced-tertiary-color)'\n : 'var(--instrument-regular-tertiary-color)';\n const setpointAngle =\n this.setpoint !== undefined ? this.getAngle(this.setpoint) : undefined;\n\n const maxDigits = 1;\n\n return html`\n <div class=\"container\">\n <obc-watch\n .touching=${this.touching}\n .angleSetpoint=${setpointAngle}\n .newAngleSetpoint=${this.newSetpoint !== undefined\n ? this.getAngle(this.newSetpoint)\n : undefined}\n .atAngleSetpoint=${this.computeAtSetpoint(this.speed)}\n .angleSetpointAtZeroDeadband=${this.setpointAtZeroDeadband}\n .setpointOverride=${this.setpointOverride}\n .animateSetpoint=${this.animateSetpoint}\n .padding=${48}\n .tickmarks=${this.tickmarks}\n .tickmarksInside=${this.tickmarksInside}\n .tickmarkStyle=${this.tickmarkStyle}\n .advices=${this._advices}\n .areas=${[\n {\n startAngle: this.minAngle,\n endAngle: this.maxAngle,\n roundInsideCut: true,\n roundOutsideCut: true,\n },\n ]}\n .watchCircleType=${WatchCircleType.double}\n .barAreas=${[\n {\n startAngle: this.getAngle(0),\n endAngle: this.getAngle(this.speed),\n fillColor: barColor,\n },\n ]}\n ></obc-watch>\n <svg class=\"rudder\" viewBox=\"-224 -224 448 448\">${this.needle}</svg>\n ${this.hasReadout\n ? html`\n ${renderInstrumentReadout({\n className: 'speed-gauge-value',\n direction: ReadoutDirection.horizontal,\n value: this.speed,\n label: this.label,\n unit: this.unit,\n fractionDigits: this.fractionDigits,\n maxDigits,\n priority: this.priority,\n })}\n `\n : nothing}\n </div>\n `;\n }\n\n get needle() {\n const needleColor =\n this.priority === Priority.enhanced\n ? 'var(--instrument-enhanced-secondary-color)'\n : 'var(--instrument-regular-secondary-color)';\n if (this.needleType === ObcSpeedGaugeNeedleType.full) {\n return svg`<g transform=\"rotate(${this.getAngle(this.speed)}) translate(-256, -256)\">\n <circle cx=\"256\" cy=\"256\" r=\"14\" fill=${needleColor}/>\n <rect x=\"250\" y=\"96\" width=\"12\" height=\"192\" rx=\"6\" fill=${needleColor}/>\n <rect x=\"252\" y=\"98\" width=\"8\" height=\"188\" rx=\"4\" stroke=${needleColor} fill=${needleColor} stroke-width=\"4\"/>\n </svg> \n`;\n } else {\n return svg`<g transform=\"rotate(${this.getAngle(this.speed)}) translate(-256, -256)\">\n<rect x=\"252\" y=\"96\" width=\"8\" height=\"48\" rx=\"4\" fill=${needleColor} stroke=\"var(--border-silhouette-color)\"/>\n</svg>\n `;\n }\n }\n\n get tickmarks(): Tickmark[] {\n const tickmarks: Tickmark[] = [];\n\n // Tickmarks — skip when undefined or <= 0 to prevent infinite loops\n const interval = this.tickmarkInterval;\n if (interval !== undefined && interval > 0 && Number.isFinite(interval)) {\n for (let i = interval; i < this.maxSpeed; i += interval) {\n tickmarks.push({\n angle: this.getAngle(i),\n type: TickmarkType.primary,\n text: this.showLabels ? i.toString() : undefined,\n });\n }\n\n if (this.showLabels && this.maxSpeed % interval === 0) {\n tickmarks.push({\n angle: this.getAngle(this.maxSpeed),\n type: TickmarkType.textOnly,\n text: this.showLabels ? this.maxSpeed.toString() : undefined,\n });\n }\n\n for (let i = -interval; i > this.minSpeed; i -= interval) {\n tickmarks.push({\n angle: this.getAngle(i),\n type: TickmarkType.main,\n text: this.showLabels ? i.toString() : undefined,\n });\n }\n\n if (this.showLabels && this.minSpeed % interval === 0) {\n tickmarks.push({\n angle: this.getAngle(this.minSpeed),\n type: TickmarkType.textOnly,\n text: this.showLabels ? this.minSpeed.toString() : undefined,\n });\n }\n }\n\n // Zero tickmark\n tickmarks.push({\n angle: this.getAngle(0),\n type: this.minSpeed < 0 ? TickmarkType.main : TickmarkType.textOnly,\n text: this.showLabels ? '0' : undefined,\n });\n\n return tickmarks;\n }\n\n get _advices(): AngleAdviceRaw[] {\n return this.speedAdvices.map((speedAdvice) => {\n const minAngle = this.getAngle(speedAdvice.minSpeed);\n const maxAngle = this.getAngle(speedAdvice.maxSpeed);\n let state = speedAdvice.hinted ? AdviceState.hinted : AdviceState.regular;\n if (\n this.speed >= speedAdvice.minSpeed &&\n this.speed <= speedAdvice.maxSpeed\n ) {\n state = AdviceState.triggered;\n }\n\n return {\n minAngle,\n maxAngle,\n type: speedAdvice.type,\n state,\n hideMinTickmark: speedAdvice.minSpeed === this.minSpeed,\n hideMaxTickmark: speedAdvice.maxSpeed === this.maxSpeed,\n };\n });\n }\n\n static override styles = css`\n * {\n box-sizing: border-box;\n }\n\n .container {\n position: relative;\n width: 100%;\n height: 100%;\n }\n\n .container > * {\n position: absolute;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n }\n\n obc-watch {\n anchor-name: --watch;\n }\n\n .speed-gauge-value {\n position: absolute;\n top: clamp(\n 70%,\n calc(80% - (anchor-size(--watch height) - 200px) * 0.2),\n 80%\n );\n left: 50%;\n transform: translateX(-50%);\n width: fit-content;\n height: fit-content;\n }\n `;\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'obc-speed-gauge': ObcSpeedGauge;\n }\n}\n"],"names":["ObcSpeedGaugeNeedleType"],"mappings":";;;;;;;;;;;;;;;;;;;;AAWO,IAAK,4CAAAA,6BAAL;AACLA,2BAAA,MAAA,IAAO;AACPA,2BAAA,KAAA,IAAM;AAFI,SAAAA;AAAA,GAAA,2BAAA,CAAA,CAAA;AA2EL,IAAM,gBAAN,cAA4B,cAAc,UAAU,EAAE;AAAA,EAAtD,cAAA;AAAA,UAAA,GAAA,SAAA;AACqB,SAAA,QAAQ;AACR,SAAA,WAAW;AACX,SAAA,WAAW;AACV,SAAA,aAAsB;AAEtB,SAAA,kBAA2B;AAK5B,SAAA,mBAAuC;AACvC,SAAA,WAAqB,SAAS;AAC9B,SAAA,aACxB;AACyC,SAAA,eAA8B,CAAA;AAC/C,SAAA,gBACxB,cAAc;AAKW,SAAA,aAAsB;AAEvB,SAAA,QAAQ;AAER,SAAA,OAAO;AAEP,SAAA,iBAAiB;AAU3C,SAAA,WAAW,MAAM;AAAA,EAAA;AAAA,EARjB,SAAS,GAAmB;AAC1B,WAAQ,IAAI,KAAK,YAAa,MAAM,MAAM;AAAA,EAC5C;AAAA,EAEA,IAAI,WAAmB;AACrB,WAAO,KAAK,SAAS,KAAK,QAAQ,IAAI;AAAA,EACxC;AAAA,EAIS,SAAS;AAChB,UAAM,WACJ,KAAK,aAAa,SAAS,WACvB,8CACA;AACN,UAAM,gBACJ,KAAK,aAAa,SAAY,KAAK,SAAS,KAAK,QAAQ,IAAI;AAE/D,UAAM,YAAY;AAElB,WAAO;AAAA;AAAA;AAAA,sBAGW,KAAK,QAAQ;AAAA,2BACR,aAAa;AAAA,8BACV,KAAK,gBAAgB,SACrC,KAAK,SAAS,KAAK,WAAW,IAC9B,MAAS;AAAA,6BACM,KAAK,kBAAkB,KAAK,KAAK,CAAC;AAAA,yCACtB,KAAK,sBAAsB;AAAA,8BACtC,KAAK,gBAAgB;AAAA,6BACtB,KAAK,eAAe;AAAA,qBAC5B,EAAE;AAAA,uBACA,KAAK,SAAS;AAAA,6BACR,KAAK,eAAe;AAAA,2BACtB,KAAK,aAAa;AAAA,qBACxB,KAAK,QAAQ;AAAA,mBACf;AAAA,MACP;AAAA,QACE,YAAY,KAAK;AAAA,QACjB,UAAU,KAAK;AAAA,QACf,gBAAgB;AAAA,QAChB,iBAAiB;AAAA,MAAA;AAAA,IACnB,CACD;AAAA,6BACkB,gBAAgB,MAAM;AAAA,sBAC7B;AAAA,MACV;AAAA,QACE,YAAY,KAAK,SAAS,CAAC;AAAA,QAC3B,UAAU,KAAK,SAAS,KAAK,KAAK;AAAA,QAClC,WAAW;AAAA,MAAA;AAAA,IACb,CACD;AAAA;AAAA,0DAE+C,KAAK,MAAM;AAAA,UAC3D,KAAK,aACH;AAAA,gBACI,wBAAwB;AAAA,MACxB,WAAW;AAAA,MACX,WAAW,iBAAiB;AAAA,MAC5B,OAAO,KAAK;AAAA,MACZ,OAAO,KAAK;AAAA,MACZ,MAAM,KAAK;AAAA,MACX,gBAAgB,KAAK;AAAA,MACrB;AAAA,MACA,UAAU,KAAK;AAAA,IAAA,CAChB,CAAC;AAAA,gBAEJ,OAAO;AAAA;AAAA;AAAA,EAGjB;AAAA,EAEA,IAAI,SAAS;AACX,UAAM,cACJ,KAAK,aAAa,SAAS,WACvB,+CACA;AACN,QAAI,KAAK,eAAe,QAA8B;AACpD,aAAO,2BAA2B,KAAK,SAAS,KAAK,KAAK,CAAC;AAAA,8CACnB,WAAW;AAAA,iEACQ,WAAW;AAAA,kEACV,WAAW,SAAS,WAAW;AAAA;AAAA;AAAA,IAG7F,OAAO;AACL,aAAO,2BAA2B,KAAK,SAAS,KAAK,KAAK,CAAC;AAAA,yDACR,WAAW;AAAA;AAAA;AAAA,IAGhE;AAAA,EACF;AAAA,EAEA,IAAI,YAAwB;AAC1B,UAAM,YAAwB,CAAA;AAG9B,UAAM,WAAW,KAAK;AACtB,QAAI,aAAa,UAAa,WAAW,KAAK,OAAO,SAAS,QAAQ,GAAG;AACvE,eAAS,IAAI,UAAU,IAAI,KAAK,UAAU,KAAK,UAAU;AACvD,kBAAU,KAAK;AAAA,UACb,OAAO,KAAK,SAAS,CAAC;AAAA,UACtB,MAAM,aAAa;AAAA,UACnB,MAAM,KAAK,aAAa,EAAE,aAAa;AAAA,QAAA,CACxC;AAAA,MACH;AAEA,UAAI,KAAK,cAAc,KAAK,WAAW,aAAa,GAAG;AACrD,kBAAU,KAAK;AAAA,UACb,OAAO,KAAK,SAAS,KAAK,QAAQ;AAAA,UAClC,MAAM,aAAa;AAAA,UACnB,MAAM,KAAK,aAAa,KAAK,SAAS,aAAa;AAAA,QAAA,CACpD;AAAA,MACH;AAEA,eAAS,IAAI,CAAC,UAAU,IAAI,KAAK,UAAU,KAAK,UAAU;AACxD,kBAAU,KAAK;AAAA,UACb,OAAO,KAAK,SAAS,CAAC;AAAA,UACtB,MAAM,aAAa;AAAA,UACnB,MAAM,KAAK,aAAa,EAAE,aAAa;AAAA,QAAA,CACxC;AAAA,MACH;AAEA,UAAI,KAAK,cAAc,KAAK,WAAW,aAAa,GAAG;AACrD,kBAAU,KAAK;AAAA,UACb,OAAO,KAAK,SAAS,KAAK,QAAQ;AAAA,UAClC,MAAM,aAAa;AAAA,UACnB,MAAM,KAAK,aAAa,KAAK,SAAS,aAAa;AAAA,QAAA,CACpD;AAAA,MACH;AAAA,IACF;AAGA,cAAU,KAAK;AAAA,MACb,OAAO,KAAK,SAAS,CAAC;AAAA,MACtB,MAAM,KAAK,WAAW,IAAI,aAAa,OAAO,aAAa;AAAA,MAC3D,MAAM,KAAK,aAAa,MAAM;AAAA,IAAA,CAC/B;AAED,WAAO;AAAA,EACT;AAAA,EAEA,IAAI,WAA6B;AAC/B,WAAO,KAAK,aAAa,IAAI,CAAC,gBAAgB;AAC5C,YAAM,WAAW,KAAK,SAAS,YAAY,QAAQ;AACnD,YAAM,WAAW,KAAK,SAAS,YAAY,QAAQ;AACnD,UAAI,QAAQ,YAAY,SAAS,YAAY,SAAS,YAAY;AAClE,UACE,KAAK,SAAS,YAAY,YAC1B,KAAK,SAAS,YAAY,UAC1B;AACA,gBAAQ,YAAY;AAAA,MACtB;AAEA,aAAO;AAAA,QACL;AAAA,QACA;AAAA,QACA,MAAM,YAAY;AAAA,QAClB;AAAA,QACA,iBAAiB,YAAY,aAAa,KAAK;AAAA,QAC/C,iBAAiB,YAAY,aAAa,KAAK;AAAA,MAAA;AAAA,IAEnD,CAAC;AAAA,EACH;AAsCF;AAvOa,cAmMK,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAlMC,gBAAA;AAAA,EAAzB,SAAS,EAAC,MAAM,OAAA,CAAO;AAAA,GADb,cACe,WAAA,SAAA,CAAA;AACA,gBAAA;AAAA,EAAzB,SAAS,EAAC,MAAM,OAAA,CAAO;AAAA,GAFb,cAEe,WAAA,YAAA,CAAA;AACA,gBAAA;AAAA,EAAzB,SAAS,EAAC,MAAM,OAAA,CAAO;AAAA,GAHb,cAGe,WAAA,YAAA,CAAA;AACC,gBAAA;AAAA,EAA1B,SAAS,EAAC,MAAM,QAAA,CAAQ;AAAA,GAJd,cAIgB,WAAA,cAAA,CAAA;AAEA,gBAAA;AAAA,EAA1B,SAAS,EAAC,MAAM,QAAA,CAAQ;AAAA,GANd,cAMgB,WAAA,mBAAA,CAAA;AAKD,gBAAA;AAAA,EAAzB,SAAS,EAAC,MAAM,OAAA,CAAO;AAAA,GAXb,cAWe,WAAA,oBAAA,CAAA;AACA,gBAAA;AAAA,EAAzB,SAAS,EAAC,MAAM,OAAA,CAAO;AAAA,GAZb,cAYe,WAAA,YAAA,CAAA;AACA,gBAAA;AAAA,EAAzB,SAAS,EAAC,MAAM,OAAA,CAAO;AAAA,GAbb,cAae,WAAA,cAAA,CAAA;AAEiB,gBAAA;AAAA,EAA1C,SAAS,EAAC,MAAM,OAAO,WAAW,OAAM;AAAA,GAf9B,cAegC,WAAA,gBAAA,CAAA;AACjB,gBAAA;AAAA,EAAzB,SAAS,EAAC,MAAM,OAAA,CAAO;AAAA,GAhBb,cAgBe,WAAA,iBAAA,CAAA;AAMC,gBAAA;AAAA,EAA1B,SAAS,EAAC,MAAM,QAAA,CAAQ;AAAA,GAtBd,cAsBgB,WAAA,cAAA,CAAA;AAED,gBAAA;AAAA,EAAzB,SAAS,EAAC,MAAM,OAAA,CAAO;AAAA,GAxBb,cAwBe,WAAA,SAAA,CAAA;AAEA,gBAAA;AAAA,EAAzB,SAAS,EAAC,MAAM,OAAA,CAAO;AAAA,GA1Bb,cA0Be,WAAA,QAAA,CAAA;AAEA,gBAAA;AAAA,EAAzB,SAAS,EAAC,MAAM,OAAA,CAAO;AAAA,GA5Bb,cA4Be,WAAA,kBAAA,CAAA;AA5Bf,gBAAN,gBAAA;AAAA,EADN,cAAc,iBAAiB;AAAA,GACnB,aAAA;"}
|
|
1
|
+
{"version":3,"file":"speed-gauge.js","sources":["../../../src/navigation-instruments/speed-gauge/speed-gauge.ts"],"sourcesContent":["import {LitElement, PropertyValues, css, html, nothing, svg} from 'lit';\nimport {property} from 'lit/decorators.js';\nimport {ResizeController} from '@lit-labs/observers/resize-controller.js';\nimport {\n applyPinnedHostSize,\n computeRadialFrame,\n estimateLabelWidthPx,\n measureContainerPx,\n observeInnerBox,\n type RadialFrame,\n} from '../../svghelpers/radial-frame.js';\nimport {Tickmark, TickmarkStyle, TickmarkType} from '../watch/tickmark.js';\nimport {WatchCircleType} from '../watch/watch.js';\nimport {AdviceType, AngleAdviceRaw, AdviceState} from '../watch/advice.js';\nimport {SetpointMixin} from '../../svghelpers/setpoint-mixin.js';\nimport {Priority} from '../types.js';\nimport {renderInstrumentReadout} from '../readout/instrument-readout.js';\nimport {ReadoutDirection} from '../readout/readout.js';\nimport {customElement} from '../../decorator.js';\n\nexport enum ObcSpeedGaugeNeedleType {\n full = 'full',\n bar = 'bar',\n}\n\nexport interface SpeedAdvice {\n minSpeed: number;\n maxSpeed: number;\n type: AdviceType;\n hinted: boolean;\n}\n\n/**\n * `<obc-speed-gauge>` — Radial speed gauge with needle and optional readout.\n *\n * `ObcSpeedGauge` renders a 225° arc gauge (−90° to +135°) that displays\n * the current speed with a configurable full-length or bar needle. It layers\n * an `<obc-watch>` base with a needle SVG overlay and an optional numeric\n * readout field. It inherits a full setpoint property bundle from\n * {@link SetpointMixin}, including auto at-setpoint detection, dual-marker\n * adjustment preview, and deadband tuning.\n *\n * ## Features\n *\n * - **Two needle types**: `full` (pointer with center dot) and `bar`\n * (short indicator bar) via `needleType`.\n * - **Bipolar range support**: When `minSpeed < 0`, negative tickmarks are\n * rendered with `main` tick style.\n * - **Optional readout**: Enable `hasReadout` to display an\n * `<obc-readout>` with the current speed, unit (KN), and label (STW).\n * - **Setpoint via mixin**: `setpoint`, `newSetpoint`, `touching`,\n * `autoAtSetpointDeadband`, `setpointOverride`, and all other setpoint\n * properties are provided by `SetpointMixin`; the setpoint angle and\n * at-setpoint state are computed and forwarded to `<obc-watch>`.\n * - **Speed advice zones**: Pass an array of {@link SpeedAdvice} objects to\n * render caution/alert arcs; triggered state is derived from whether the\n * current speed falls inside the advice range.\n *\n * ## Usage Guidelines\n *\n * - Set `maxSpeed` (and optionally `minSpeed`) to define the gauge range.\n * - Use `priority` to switch between regular and enhanced color palettes\n * (default: `Priority.regular`).\n * - Provide `tickmarkInterval` to control tickmark spacing.\n * - Enable `showLabels` to show numeric labels at primary tickmarks.\n * - Enable `tickmarksInside` to render tickmarks inside the ring.\n * - Enable `hasReadout` to display the numeric value below the gauge.\n *\n * ## Best Practices\n *\n * - Prefer `SetpointMixin` properties (`setpoint`, `touching`, etc.) over\n * any legacy aliases — the mixin is the single source of truth.\n * - The needle overlay SVG uses viewBox `−224 −224 448 448` to align with\n * the `<obc-watch>` layer.\n *\n * ## Example\n *\n * ```html\n * <obc-speed-gauge\n * speed=\"12.5\"\n * maxSpeed=\"25\"\n * needleType=\"full\"\n * enhanced\n * showLabels\n * hasReadout\n * tickmarkInterval=\"5\"\n * setpoint=\"15\"\n * ></obc-speed-gauge>\n * ```\n *\n * @element obc-speed-gauge\n * @typedef {import('./speed-gauge.js').SpeedAdvice} SpeedAdvice\n * @stable\n */\n@customElement('obc-speed-gauge')\nexport class ObcSpeedGauge extends SetpointMixin(LitElement) {\n @property({type: Number}) speed = 0;\n @property({type: Number}) maxSpeed = 100;\n @property({type: Number}) minSpeed = 0;\n @property({type: Boolean}) showLabels: boolean = false;\n /** Whether to render tickmarks inside the ring. */\n @property({type: Boolean}) tickmarksInside: boolean = false;\n /**\n * Interval for tickmarks in speed units.\n * When undefined or <= 0, no tickmarks are shown (only the zero mark).\n */\n @property({type: Number}) tickmarkInterval: number | undefined = 20;\n @property({type: String}) priority: Priority = Priority.regular;\n @property({type: String}) needleType: ObcSpeedGaugeNeedleType =\n ObcSpeedGaugeNeedleType.full;\n @property({type: Array, attribute: false}) speedAdvices: SpeedAdvice[] = [];\n @property({type: String}) tickmarkStyle: TickmarkStyle =\n TickmarkStyle.regular;\n /**\n * When `true`, shows a centered `<obc-readout>` (label `STW`, unit `KN`)\n * below the gauge with the current speed. Default `false`.\n */\n @property({type: Boolean}) hasReadout: boolean = false;\n /** Readout label. Default `STW`. */\n @property({type: String}) label = 'STW';\n /** Readout unit. Default `KN`. */\n @property({type: String}) unit = 'KN';\n /** Number of fraction digits shown in the readout. Default `1`. */\n @property({type: Number}) fractionDigits = 1;\n /**\n * Outer-ring diameter in CSS pixels. When set, the instrument renders at a\n * fixed intrinsic size derived from the ring, arc shape and label reserve —\n * so instruments sharing the same value have identical ring circumference\n * regardless of label width or arc extent (like obc-donut-chart's\n * fixedHeight). When unset (default), the instrument fills its container.\n */\n @property({type: Number, attribute: 'face-diameter'})\n faceDiameter: number | undefined;\n\n private _frame: RadialFrame | undefined;\n\n /** Whether the host size styles were set by applyPinnedHostSize. */\n private _hostSizePinned = false;\n\n private _resizeController = new ResizeController(this, {});\n\n override firstUpdated(changed: PropertyValues): void {\n super.firstUpdated(changed);\n observeInnerBox(this._resizeController, this.renderRoot);\n }\n\n override updated(changed: PropertyValues): void {\n super.updated(changed);\n this._hostSizePinned = applyPinnedHostSize(\n this,\n this._frame,\n this._hostSizePinned\n );\n }\n\n getAngle(v: number): number {\n return (v / this.maxSpeed) * (180 + 45) - 90;\n }\n\n get minAngle(): number {\n return this.getAngle(this.minSpeed) - 360;\n }\n\n maxAngle = 180 - 45;\n\n override render() {\n const barColor =\n this.priority === Priority.enhanced\n ? 'var(--instrument-enhanced-tertiary-color)'\n : 'var(--instrument-regular-tertiary-color)';\n const setpointAngle =\n this.setpoint !== undefined ? this.getAngle(this.setpoint) : undefined;\n\n const maxDigits = 1;\n\n const tickmarks = this.tickmarks;\n const frame = computeRadialFrame({\n basePadding: 48,\n labelWidthPx: this.tickmarksInside\n ? 0\n : estimateLabelWidthPx(tickmarks.map((t) => t.text)),\n containerPx: measureContainerPx(this),\n faceDiameter: this.faceDiameter,\n });\n this._frame = frame;\n const shownTickmarks = frame.labelsHidden\n ? tickmarks.map((t) => ({...t, text: undefined}))\n : tickmarks;\n\n return html`\n <div class=\"container\">\n <obc-watch\n .touching=${this.touching}\n .angleSetpoint=${setpointAngle}\n .newAngleSetpoint=${this.newSetpoint !== undefined\n ? this.getAngle(this.newSetpoint)\n : undefined}\n .atAngleSetpoint=${this.computeAtSetpoint(this.speed)}\n .angleSetpointAtZeroDeadband=${this.setpointAtZeroDeadband}\n .setpointOverride=${this.setpointOverride}\n .animateSetpoint=${this.animateSetpoint}\n .arcFrame=${frame}\n .tickmarks=${shownTickmarks}\n .tickmarksInside=${this.tickmarksInside}\n .tickmarkStyle=${this.tickmarkStyle}\n .advices=${this._advices}\n .areas=${[\n {\n startAngle: this.minAngle,\n endAngle: this.maxAngle,\n roundInsideCut: true,\n roundOutsideCut: true,\n },\n ]}\n .watchCircleType=${WatchCircleType.double}\n .barAreas=${[\n {\n startAngle: this.getAngle(0),\n endAngle: this.getAngle(this.speed),\n fillColor: barColor,\n },\n ]}\n ></obc-watch>\n <svg class=\"rudder\" viewBox=${frame.viewBox}>${this.needle}</svg>\n ${this.hasReadout\n ? html`\n ${renderInstrumentReadout({\n className: 'speed-gauge-value',\n direction: ReadoutDirection.horizontal,\n value: this.speed,\n label: this.label,\n unit: this.unit,\n fractionDigits: this.fractionDigits,\n maxDigits,\n priority: this.priority,\n })}\n `\n : nothing}\n </div>\n `;\n }\n\n get needle() {\n const needleColor =\n this.priority === Priority.enhanced\n ? 'var(--instrument-enhanced-secondary-color)'\n : 'var(--instrument-regular-secondary-color)';\n if (this.needleType === ObcSpeedGaugeNeedleType.full) {\n return svg`<g transform=\"rotate(${this.getAngle(this.speed)}) translate(-256, -256)\">\n <circle cx=\"256\" cy=\"256\" r=\"14\" fill=${needleColor}/>\n <rect x=\"250\" y=\"96\" width=\"12\" height=\"192\" rx=\"6\" fill=${needleColor}/>\n <rect x=\"252\" y=\"98\" width=\"8\" height=\"188\" rx=\"4\" stroke=${needleColor} fill=${needleColor} stroke-width=\"4\"/>\n </svg> \n`;\n } else {\n return svg`<g transform=\"rotate(${this.getAngle(this.speed)}) translate(-256, -256)\">\n<rect x=\"252\" y=\"96\" width=\"8\" height=\"48\" rx=\"4\" fill=${needleColor} stroke=\"var(--border-silhouette-color)\"/>\n</svg>\n `;\n }\n }\n\n get tickmarks(): Tickmark[] {\n const tickmarks: Tickmark[] = [];\n\n // Tickmarks — skip when undefined or <= 0 to prevent infinite loops\n const interval = this.tickmarkInterval;\n if (interval !== undefined && interval > 0 && Number.isFinite(interval)) {\n for (let i = interval; i < this.maxSpeed; i += interval) {\n tickmarks.push({\n angle: this.getAngle(i),\n type: TickmarkType.primary,\n text: this.showLabels ? i.toString() : undefined,\n });\n }\n\n if (this.showLabels && this.maxSpeed % interval === 0) {\n tickmarks.push({\n angle: this.getAngle(this.maxSpeed),\n type: TickmarkType.textOnly,\n text: this.showLabels ? this.maxSpeed.toString() : undefined,\n });\n }\n\n for (let i = -interval; i > this.minSpeed; i -= interval) {\n tickmarks.push({\n angle: this.getAngle(i),\n type: TickmarkType.main,\n text: this.showLabels ? i.toString() : undefined,\n });\n }\n\n if (this.showLabels && this.minSpeed % interval === 0) {\n tickmarks.push({\n angle: this.getAngle(this.minSpeed),\n type: TickmarkType.textOnly,\n text: this.showLabels ? this.minSpeed.toString() : undefined,\n });\n }\n }\n\n // Zero tickmark\n tickmarks.push({\n angle: this.getAngle(0),\n type: this.minSpeed < 0 ? TickmarkType.main : TickmarkType.textOnly,\n text: this.showLabels ? '0' : undefined,\n });\n\n return tickmarks;\n }\n\n get _advices(): AngleAdviceRaw[] {\n return this.speedAdvices.map((speedAdvice) => {\n const minAngle = this.getAngle(speedAdvice.minSpeed);\n const maxAngle = this.getAngle(speedAdvice.maxSpeed);\n let state = speedAdvice.hinted ? AdviceState.hinted : AdviceState.regular;\n if (\n this.speed >= speedAdvice.minSpeed &&\n this.speed <= speedAdvice.maxSpeed\n ) {\n state = AdviceState.triggered;\n }\n\n return {\n minAngle,\n maxAngle,\n type: speedAdvice.type,\n state,\n hideMinTickmark: speedAdvice.minSpeed === this.minSpeed,\n hideMaxTickmark: speedAdvice.maxSpeed === this.maxSpeed,\n };\n });\n }\n\n static override styles = css`\n * {\n box-sizing: border-box;\n }\n\n .container {\n position: relative;\n width: 100%;\n height: 100%;\n }\n\n .container > * {\n position: absolute;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n }\n\n obc-watch {\n anchor-name: --watch;\n }\n\n .speed-gauge-value {\n position: absolute;\n top: clamp(\n 70%,\n calc(80% - (anchor-size(--watch height) - 200px) * 0.2),\n 80%\n );\n left: 50%;\n transform: translateX(-50%);\n width: fit-content;\n height: fit-content;\n }\n `;\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'obc-speed-gauge': ObcSpeedGauge;\n }\n}\n"],"names":["ObcSpeedGaugeNeedleType"],"mappings":"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"}
|
|
@@ -85,36 +85,27 @@ export declare function innerRingRadiusFor(type: WatchCircleType): number;
|
|
|
85
85
|
* `_setpointCssAngle` tracks the accumulated CSS angle to avoid long-way-around
|
|
86
86
|
* transitions across the 0°/360° boundary.
|
|
87
87
|
*
|
|
88
|
-
* @property {InstrumentState} state - Instrument state (active, loading, off)
|
|
89
|
-
* @property {Priority} priority - Color priority (enhanced = blue palette, regular = gray palette)
|
|
90
|
-
* @property {number|undefined} angleSetpoint - Setpoint angle in degrees (0° = 12 o'clock)
|
|
91
|
-
* @property {number|undefined} newAngleSetpoint - New setpoint being adjusted (focus mode)
|
|
92
|
-
* @property {boolean} atAngleSetpoint - Whether value matches setpoint (within deadband)
|
|
93
|
-
* @property {number} angleSetpointAtZeroDeadband - Deadband for zero detection (default 0.5°)
|
|
94
|
-
* @property {boolean} setpointOverride - Override to derive setpoint color from priority regardless of state
|
|
95
|
-
* @property {RotType|undefined} rotType - ROT visualization type: `'dots'` (spinning dots) or `'bar'` (arc bar with clipped dots). Undefined hides the ROT layer.
|
|
96
|
-
* @property {RotPosition} rotPosition - Track on which ROT elements are placed: `'scale'` (on the outer ring) or `'innerCircle'` (default, inside the inner ring)
|
|
97
|
-
* @property {number} rotStartAngle - Start angle of the ROT bar arc in degrees (0° = 12 o'clock, clockwise). Only used when `rotType` is `'bar'`.
|
|
98
|
-
* @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°.
|
|
99
|
-
* @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).
|
|
100
|
-
* @property {number|undefined} rateOfTurnDegreesPerMinute - Measured rate of turn in degrees per minute (the maritime/AIS convention, see ES-TRIN 2025/1 Art. 3.02 and ITU-R M.1371). Sign controls direction (positive = starboard/clockwise). When defined, this drives both the dot animation (multiplied by `rotDotAnimationFactor`) and the port/starboard direction sign.
|
|
101
|
-
* @property {number} rotDotAnimationFactor - Visual amplification factor applied only to the spinning-dot animation (not to bar extent). Default `18` keeps the legacy visual feel (≈1 rpm at 20°/min).
|
|
102
|
-
* @property {number} rotationsPerMinute - **Deprecated.** Spin speed of the ROT dot ring in rotations per minute. Sign controls direction (positive = clockwise). Use `rateOfTurnDegreesPerMinute` instead.
|
|
103
|
-
* @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. If you pass `arcFrame`, you own keeping it in sync with `areas` / `watchCircleType` — obc-watch will NOT recompute it, so a stale frame renders stale geometry.
|
|
104
88
|
* @experimental
|
|
105
89
|
*/
|
|
106
90
|
export declare class ObcWatch extends LitElement {
|
|
107
91
|
private _setpointId;
|
|
108
92
|
private _newSetpointId;
|
|
93
|
+
/** Instrument state (active, loading, off) */
|
|
109
94
|
state: InstrumentState;
|
|
95
|
+
/** Color priority (enhanced = blue palette, regular = gray palette) */
|
|
110
96
|
priority: Priority;
|
|
111
97
|
watchCircleType: WatchCircleType;
|
|
112
98
|
northArrow: boolean;
|
|
113
99
|
northArrowInside: boolean | undefined;
|
|
100
|
+
/** Setpoint angle in degrees (0° = 12 o'clock) */
|
|
114
101
|
angleSetpoint: number | undefined;
|
|
102
|
+
/** New setpoint being adjusted (focus mode) */
|
|
115
103
|
newAngleSetpoint: number | undefined;
|
|
104
|
+
/** Whether value matches setpoint (within deadband) */
|
|
116
105
|
atAngleSetpoint: boolean;
|
|
106
|
+
/** Deadband for zero detection (default 0.5°) */
|
|
117
107
|
angleSetpointAtZeroDeadband: number;
|
|
108
|
+
/** Override to derive setpoint color from priority regardless of state */
|
|
118
109
|
setpointOverride: boolean;
|
|
119
110
|
touching: boolean;
|
|
120
111
|
animateSetpoint: boolean;
|
|
@@ -128,7 +119,20 @@ export declare class ObcWatch extends LitElement {
|
|
|
128
119
|
private _setpointCssAngle;
|
|
129
120
|
/** Whether the setpoint CSS angle has been initialised (to skip transition on first render). */
|
|
130
121
|
private _setpointCssAngleInit;
|
|
122
|
+
/**
|
|
123
|
+
* Explicit padding override in SVG units: the un-zoomed viewBox becomes
|
|
124
|
+
* exactly `(176 + padding) * 2`. Setting it disables the automatic
|
|
125
|
+
* width-aware label reserve (issue #1021) — the caller owns label room.
|
|
126
|
+
*/
|
|
131
127
|
padding: number | undefined;
|
|
128
|
+
/**
|
|
129
|
+
* Outer-ring diameter in CSS pixels. When set, the instrument renders at a
|
|
130
|
+
* fixed intrinsic size derived from the ring, arc shape and label reserve —
|
|
131
|
+
* so instruments sharing the same value have identical ring circumference
|
|
132
|
+
* regardless of label width or arc extent (like obc-donut-chart's
|
|
133
|
+
* fixedHeight). When unset (default), the instrument fills its container.
|
|
134
|
+
*/
|
|
135
|
+
faceDiameter: number | undefined;
|
|
132
136
|
areas: WatchArea[];
|
|
133
137
|
barAreas: WatchBarArea[];
|
|
134
138
|
needles: WatchNeedle[];
|
|
@@ -166,16 +170,24 @@ export declare class ObcWatch extends LitElement {
|
|
|
166
170
|
scaleWindIcon: number;
|
|
167
171
|
rotation: number | undefined;
|
|
168
172
|
zoomToFitArc: boolean;
|
|
173
|
+
/** 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. If you pass `arcFrame`, you own keeping it in sync with `areas` / `watchCircleType` — obc-watch will NOT recompute it, so a stale frame renders stale geometry. */
|
|
169
174
|
arcFrame: ZoomToFitArcFrame | undefined;
|
|
170
175
|
tickFadeAngle: number;
|
|
176
|
+
/** ROT visualization type: `'dots'` (spinning dots) or `'bar'` (arc bar with clipped dots). Undefined hides the ROT layer. */
|
|
171
177
|
rotType: RotType | undefined;
|
|
178
|
+
/** Track on which ROT elements are placed: `'scale'` (on the outer ring) or `'innerCircle'` (default, inside the inner ring) */
|
|
172
179
|
rotPosition: RotPosition;
|
|
180
|
+
/** Start angle of the ROT bar arc in degrees (0° = 12 o'clock, clockwise). Only used when `rotType` is `'bar'`. */
|
|
173
181
|
rotStartAngle: number;
|
|
182
|
+
/** End angle of the ROT bar arc in degrees. The bar is hidden when the difference from `rotStartAngle` is less than 0.1°. */
|
|
174
183
|
rotEndAngle: number;
|
|
184
|
+
/** 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). */
|
|
175
185
|
rotPriority: Priority | undefined;
|
|
176
186
|
rotPortStarboard: boolean;
|
|
177
187
|
rotAtZeroDeadband: number;
|
|
188
|
+
/** Measured rate of turn in degrees per minute (the maritime/AIS convention, see ES-TRIN 2025/1 Art. 3.02 and ITU-R M.1371). Sign controls direction (positive = starboard/clockwise). When defined, this drives both the dot animation (multiplied by `rotDotAnimationFactor`) and the port/starboard direction sign. */
|
|
178
189
|
rateOfTurnDegreesPerMinute: number | undefined;
|
|
190
|
+
/** Visual amplification factor applied only to the spinning-dot animation (not to bar extent). Default `18` keeps the legacy visual feel (≈1 rpm at 20°/min). */
|
|
179
191
|
rotDotAnimationFactor: number;
|
|
180
192
|
/**
|
|
181
193
|
* @deprecated Use `rateOfTurnDegreesPerMinute` (and optionally `rotDotAnimationFactor`) instead.
|
|
@@ -183,6 +195,7 @@ export declare class ObcWatch extends LitElement {
|
|
|
183
195
|
* `rateOfTurnDegreesPerMinute` is `undefined`.
|
|
184
196
|
*/
|
|
185
197
|
set rotationsPerMinute(value: number);
|
|
198
|
+
/** Legacy spin speed of the ROT dot ring, in rotations per minute (sign controls direction; positive = clockwise). */
|
|
186
199
|
get rotationsPerMinute(): number;
|
|
187
200
|
private _legacyRotationsPerMinute;
|
|
188
201
|
private _rotController?;
|
|
@@ -195,11 +208,21 @@ export declare class ObcWatch extends LitElement {
|
|
|
195
208
|
*/
|
|
196
209
|
private get _effectiveRpm();
|
|
197
210
|
private _resizeController;
|
|
211
|
+
firstUpdated(changed: PropertyValues): void;
|
|
198
212
|
willUpdate(changed: PropertyValues): void;
|
|
199
213
|
disconnectedCallback(): void;
|
|
200
214
|
updated(changed: PropertyValues): void;
|
|
201
215
|
private get innerRingRadius();
|
|
202
216
|
private _rOff;
|
|
217
|
+
/**
|
|
218
|
+
* Set by the frame when the label reserve exceeded its cap: tick label
|
|
219
|
+
* texts are dropped instead of clipped (see radial-frame.ts).
|
|
220
|
+
*/
|
|
221
|
+
private _labelsHidden;
|
|
222
|
+
/** The frame of the last render, when computed internally (no arcFrame). */
|
|
223
|
+
private _ownFrame;
|
|
224
|
+
/** Whether the host size styles were set by applyPinnedHostSize. */
|
|
225
|
+
private _hostSizePinned;
|
|
203
226
|
/**
|
|
204
227
|
* Radius for a dial-band edge under zoom: additive (`base + _rOff`), keeping
|
|
205
228
|
* band thickness constant in SVG units. INVARIANT: every band-edge radius
|
|
@@ -215,7 +238,12 @@ export declare class ObcWatch extends LitElement {
|
|
|
215
238
|
private renderBars;
|
|
216
239
|
private renderNeedles;
|
|
217
240
|
private getScale;
|
|
218
|
-
|
|
241
|
+
/**
|
|
242
|
+
* Pixel width of the widest outside label, feeding the frame's label
|
|
243
|
+
* reserve (issue #1021). Explicit `padding` is a hard geometry override
|
|
244
|
+
* and disables the reserve, preserving legacy consumer output.
|
|
245
|
+
*/
|
|
246
|
+
private getLabelWidthPx;
|
|
219
247
|
render(): import('lit-html').TemplateResult<1>;
|
|
220
248
|
private getRotColors;
|
|
221
249
|
private renderRot;
|