@oicl/openbridge-webcomponents-full-bundle 2.0.0-next.45 → 2.0.0-next.49

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.
Files changed (95) hide show
  1. package/.storybook/ComponentPreview.tsx +26 -0
  2. package/.storybook/PreviewTemplate.tsx +99 -0
  3. package/.storybook/action-handler.ts +81 -0
  4. package/.storybook/channels.ts +44 -0
  5. package/.storybook/main.ts +313 -0
  6. package/.storybook/manager.ts +71 -0
  7. package/.storybook/openbridgeTheme.ts +197 -0
  8. package/.storybook/preview-head.html +15 -0
  9. package/.storybook/preview.tsx +129 -0
  10. package/.storybook/vitest.setup.ts +23 -0
  11. package/bundle/openbridge-webcomponents.bundle.js +14869 -14889
  12. package/bundle/openbridge-webcomponents.bundle.js.map +1 -1
  13. package/custom-elements.json +81 -82
  14. package/dist/components/badge/badge.css.js +15 -15
  15. package/dist/components/icon-button/icon-button.d.ts +4 -0
  16. package/dist/components/icon-button/icon-button.d.ts.map +1 -1
  17. package/dist/components/icon-button/icon-button.js.map +1 -1
  18. package/dist/navigation-instruments/compass/compass.d.ts +3 -3
  19. package/dist/navigation-instruments/compass/compass.d.ts.map +1 -1
  20. package/dist/navigation-instruments/compass/compass.js +3 -3
  21. package/dist/navigation-instruments/compass/compass.js.map +1 -1
  22. package/dist/navigation-instruments/compass-indicator/compass-indicator.d.ts +12 -0
  23. package/dist/navigation-instruments/compass-indicator/compass-indicator.d.ts.map +1 -1
  24. package/dist/navigation-instruments/compass-indicator/compass-indicator.js +9 -1
  25. package/dist/navigation-instruments/compass-indicator/compass-indicator.js.map +1 -1
  26. package/dist/navigation-instruments/velocity-projection-plot/velocity-projection-plot.d.ts +4 -4
  27. package/dist/navigation-instruments/velocity-projection-plot/velocity-projection-plot.d.ts.map +1 -1
  28. package/dist/navigation-instruments/velocity-projection-plot/velocity-projection-plot.js +15 -14
  29. package/dist/navigation-instruments/velocity-projection-plot/velocity-projection-plot.js.map +1 -1
  30. package/dist/navigation-instruments/watch/environment.d.ts +39 -1
  31. package/dist/navigation-instruments/watch/environment.d.ts.map +1 -1
  32. package/dist/navigation-instruments/watch/environment.js +71 -88
  33. package/dist/navigation-instruments/watch/environment.js.map +1 -1
  34. package/dist/navigation-instruments/watch/watch.d.ts +1 -1
  35. package/dist/navigation-instruments/watch/watch.d.ts.map +1 -1
  36. package/dist/navigation-instruments/watch/watch.js +4 -4
  37. package/dist/navigation-instruments/watch/watch.js.map +1 -1
  38. package/dist/navigation-instruments/wind/wind.d.ts +1 -1
  39. package/dist/navigation-instruments/wind/wind.d.ts.map +1 -1
  40. package/dist/navigation-instruments/wind/wind.js +3 -3
  41. package/dist/navigation-instruments/wind/wind.js.map +1 -1
  42. package/dist/navigation-instruments/wind-indicator/wind-indicator.d.ts +63 -9
  43. package/dist/navigation-instruments/wind-indicator/wind-indicator.d.ts.map +1 -1
  44. package/dist/navigation-instruments/wind-indicator/wind-indicator.js +57 -1995
  45. package/dist/navigation-instruments/wind-indicator/wind-indicator.js.map +1 -1
  46. package/dist/navigation-instruments/wind-propulsion/wind-propulsion.d.ts +1 -1
  47. package/dist/navigation-instruments/wind-propulsion/wind-propulsion.d.ts.map +1 -1
  48. package/dist/navigation-instruments/wind-propulsion/wind-propulsion.js +4 -4
  49. package/dist/navigation-instruments/wind-propulsion/wind-propulsion.js.map +1 -1
  50. package/eslint.config.mjs +589 -0
  51. package/fix-imports.mjs +185 -0
  52. package/fix-js-extensions.mjs +44 -0
  53. package/lit-localize.json +15 -0
  54. package/new-component.ts +148 -0
  55. package/package.json +56 -3
  56. package/postcss.config.mjs +195 -0
  57. package/script/check-css-mixins.ts +191 -0
  58. package/script/check-css-variables.ts +280 -0
  59. package/script/convert-icons.ts +202 -0
  60. package/script/convert-vessel-svg-to-ts.ts +110 -0
  61. package/script/docgen/README.md +95 -0
  62. package/script/docgen/docs-gen.ts +225 -0
  63. package/script/docgen/prompt-system.txt +187 -0
  64. package/script/download-alert-icons.ts +193 -0
  65. package/script/download-icons.ts +314 -0
  66. package/script/figmavariables.json +139 -0
  67. package/script/generate-bundle-entry.ts +77 -0
  68. package/script/prepare-full-bundle.ts +105 -0
  69. package/script/sort-custom-element-manifest.ts +67 -0
  70. package/src/components/badge/badge.css +15 -15
  71. package/src/components/badge/badge.stories.ts +2 -0
  72. package/src/components/icon-button/icon-button.ts +4 -0
  73. package/src/navigation-instruments/compass/compass.stories.ts +5 -2
  74. package/src/navigation-instruments/compass/compass.ts +4 -4
  75. package/src/navigation-instruments/compass-indicator/compass-indicator.stories.ts +34 -1
  76. package/src/navigation-instruments/compass-indicator/compass-indicator.ts +19 -1
  77. package/src/navigation-instruments/velocity-projection-plot/velocity-projection-plot.stories.ts +13 -13
  78. package/src/navigation-instruments/velocity-projection-plot/velocity-projection-plot.ts +15 -11
  79. package/src/navigation-instruments/watch/environment.ts +120 -87
  80. package/src/navigation-instruments/watch/watch.stories.ts +2 -2
  81. package/src/navigation-instruments/watch/watch.ts +3 -3
  82. package/src/navigation-instruments/wind/wind.stories.ts +4 -3
  83. package/src/navigation-instruments/wind/wind.ts +2 -2
  84. package/src/navigation-instruments/wind-indicator/wind-indicator.stories.ts +22 -12
  85. package/src/navigation-instruments/wind-indicator/wind-indicator.ts +91 -46
  86. package/src/navigation-instruments/wind-propulsion/wind-propulsion.stories.ts +3 -3
  87. package/src/navigation-instruments/wind-propulsion/wind-propulsion.ts +3 -3
  88. package/tsconfig.json +38 -0
  89. package/vite.config.ts +107 -0
  90. package/vitest.browser.config.ts +14 -0
  91. package/vitest.config.ts +51 -0
  92. package/xliff/es-419.xlf +111 -0
  93. package/xliff/fi-FI.xlf +139 -0
  94. package/dist/NotoSans.ttf +0 -0
  95. package/dist/oicl.svg +0 -4
@@ -1,18 +1,131 @@
1
1
  import {svg, SVGTemplateResult} from 'lit';
2
2
  import {styleMap} from 'lit/directives/style-map.js';
3
+ import '../../icons/icon-wind-true-1.js';
4
+ import '../../icons/icon-wind-true-2.js';
5
+ import '../../icons/icon-wind-true-3.js';
6
+ import '../../icons/icon-wind-true-4.js';
7
+ import '../../icons/icon-wind-true-5.js';
8
+ import '../../icons/icon-wind-true-6.js';
9
+ import '../../icons/icon-wind-true-7.js';
10
+ import '../../icons/icon-wind-true-8.js';
11
+ import '../../icons/icon-wind-true-9.js';
12
+ import '../../icons/icon-wind-true-10.js';
13
+ import '../../icons/icon-wind-true-11.js';
14
+ import '../../icons/icon-wind-true-12.js';
15
+ import '../../icons/icon-wind-true-13.js';
16
+ import '../../icons/icon-wind-true-14.js';
17
+
18
+ /**
19
+ * Number of wind barb icons available (`<obi-wind-true-1>` …
20
+ * `<obi-wind-true-14>`).
21
+ *
22
+ * The set follows the standard meteorological wind-barb convention:
23
+ * icon 1 is calm, icon 2 is shaft-only (1 kn bucket), icons 3–11 add
24
+ * one half-barb per 5 kn (5, 10, 15, …, 45 kn), icon 12 is one pennant
25
+ * (50 kn), icons 13–14 add full barbs above the pennant (60 / 70 kn).
26
+ */
27
+ const WIND_ICON_COUNT = 14;
28
+
29
+ /** Render scale applied to the 24×24 icon so it matches the historic 48×48 visual footprint on the watch dial. */
30
+ const WIND_ICON_SCALE = 2;
31
+
32
+ /**
33
+ * Tip coordinates of the `obi-wind-true-*` icons in their native 24×24 child
34
+ * space. The arrowhead tip is at approximately (12, 22.4453) — this is the
35
+ * anchor point that lands on the watch's periphery radius so the barb tail
36
+ * extends outward only (matching the legacy inline-glyph behavior).
37
+ */
38
+ const WIND_ICON_TIP_X = 12;
39
+ const WIND_ICON_TIP_Y = 22.4453;
40
+
41
+ const windIconCache = new Map<string, SVGTemplateResult>();
42
+
43
+ function getWindIconSvg(index: number): SVGTemplateResult | null {
44
+ const tagName = `obi-wind-true-${index}`;
45
+ const cached = windIconCache.get(tagName);
46
+ if (cached) {
47
+ return cached;
48
+ }
49
+ const ctor = customElements.get(tagName) as
50
+ | (new () => {icon?: SVGTemplateResult; iconCss?: SVGTemplateResult})
51
+ | undefined;
52
+ if (!ctor) {
53
+ return null;
54
+ }
55
+ const instance = new ctor();
56
+ const tpl: SVGTemplateResult | undefined = instance.icon ?? instance.iconCss;
57
+ if (!tpl) {
58
+ return null;
59
+ }
60
+ windIconCache.set(tagName, tpl);
61
+ return tpl;
62
+ }
63
+
64
+ /**
65
+ * Maps a wind speed in **knots** to a wind-barb icon index in `[1, 14]`.
66
+ *
67
+ * Implements the designer-confirmed "Option C" mapping: speeds round to
68
+ * the nearest 5-knot bucket (with two sub-pennant buckets for calm and
69
+ * near-calm conditions):
70
+ *
71
+ * | Knots range | Icon | Glyph |
72
+ * | ----------- | ---- | -------------------- |
73
+ * | `[0, 0.5)` | 1 | calm |
74
+ * | `[0.5, 2.5)`| 2 | shaft only |
75
+ * | `[2.5, 7.5)`| 3 | shaft + ½ barb |
76
+ * | `[7.5, 12.5)`| 4 | shaft + 1 full barb |
77
+ * | …5-kn steps…| … | … |
78
+ * | `[42.5, 47.5)`| 11 | shaft + 4 full + ½ |
79
+ * | `[47.5, 55)`| 12 | pennant (50 kn) |
80
+ * | `[55, 65)` | 13 | pennant + 1 full barb |
81
+ * | `[65, ∞)` | 14 | pennant + 2 full barbs |
82
+ *
83
+ * The 55 / 65 / 100-knot buckets currently collapse to the nearest
84
+ * available icon; dedicated glyphs are tracked for a follow-up icon
85
+ * refresh. Non-finite / null / undefined inputs fall back to icon 1.
86
+ */
87
+ export function windKnotsToIconIndex(knots: number | null | undefined): number {
88
+ if (knots == null || !Number.isFinite(knots) || knots < 0.5) {
89
+ return 1;
90
+ }
91
+ if (knots < 2.5) {
92
+ return 2;
93
+ }
94
+ if (knots < 47.5) {
95
+ return Math.round(knots / 5) + 2;
96
+ }
97
+ if (knots < 55) {
98
+ return 12;
99
+ }
100
+ if (knots < 65) {
101
+ return 13;
102
+ }
103
+ return WIND_ICON_COUNT;
104
+ }
3
105
 
4
106
  export function renderWind(options: {
5
- wind: number;
107
+ windKnots: number;
6
108
  fromDirectionDeg: number;
7
109
  radius: number;
8
110
  color?: string;
9
111
  }): SVGTemplateResult {
10
- return renderEnvironment({
11
- filename: `wind-${options.wind + 1}.svg`,
12
- fromDirectionDeg: options.fromDirectionDeg,
13
- radius: options.radius,
14
- color: options.color,
15
- });
112
+ const {windKnots, fromDirectionDeg, radius, color} = options;
113
+ const index = windKnotsToIconIndex(windKnots);
114
+ const icon = getWindIconSvg(index);
115
+ if (!icon) {
116
+ return svg``;
117
+ }
118
+ const dirRad = (fromDirectionDeg * Math.PI) / 180;
119
+ const x = Math.sin(dirRad) * radius;
120
+ const y = -Math.cos(dirRad) * radius;
121
+ const tipX = WIND_ICON_TIP_X * WIND_ICON_SCALE;
122
+ const tipY = WIND_ICON_TIP_Y * WIND_ICON_SCALE;
123
+ const styles = {
124
+ color: color ?? 'var(--instrument-regular-secondary-color)',
125
+ };
126
+ return svg`<g style=${styleMap(styles)} transform="translate(${x} ${y}) rotate(${fromDirectionDeg}) translate(${-tipX} ${-tipY}) scale(${WIND_ICON_SCALE})">
127
+ ${icon}
128
+ </g>`;
16
129
  }
17
130
 
18
131
  export function renderCurrent(options: {
@@ -73,84 +186,4 @@ export const environmentSvgs: Record<string, SVGTemplateResult> = {
73
186
  <path fill-rule="evenodd" clip-rule="evenodd" d="M7 10.5858L12.2071 5.37866L17.4142 10.5858L16 12L12.2071 8.20709L8.41421 12L7 10.5858Z" fill="var(--instrument-regular-secondary-color)"/>
74
187
  <path fill-rule="evenodd" clip-rule="evenodd" d="M7 16.5858L12.2071 11.3787L17.4142 16.5858L16 18L12.2071 14.2071L8.41421 18L7 16.5858Z" fill="var(--instrument-regular-secondary-color)"/>
75
188
  <path fill-rule="evenodd" clip-rule="evenodd" d="M7 22.5858L12.2071 17.3787L17.4142 22.5858L16 24L12.2071 20.2071L8.41421 24L7 22.5858Z" fill="var(--instrument-regular-secondary-color)"/>`,
76
- 'wind-1.svg': svg`<path d="M12 2C6.47715 2 2 6.47715 2 12H3.90476C3.90476 7.52912 7.52912 3.90476 12 3.90476V2Z" stroke="var(--border-silhouette-color)" stroke-width="2"/>
77
- <path d="M22 12C22 6.47715 17.5228 2 12 2V3.90476C16.4709 3.90476 20.0952 7.52912 20.0952 12H22Z" stroke="var(--border-silhouette-color)" stroke-width="2"/>
78
- <path d="M12 22C17.5228 22 22 17.5228 22 12H20.0952C20.0952 16.4709 16.4709 20.0952 12 20.0952V22Z" stroke="var(--border-silhouette-color)" stroke-width="2"/>
79
- <path d="M2 12C2 17.5228 6.47715 22 12 22V20.0952C7.52912 20.0952 3.90476 16.4709 3.90476 12H2Z" stroke="var(--border-silhouette-color)" stroke-width="2"/>
80
- <path d="M12 2C6.47715 2 2 6.47715 2 12H3.90476C3.90476 7.52912 7.52912 3.90476 12 3.90476V2Z" fill="var(--instrument-regular-secondary-color)"/>
81
- <path d="M22 12C22 6.47715 17.5228 2 12 2V3.90476C16.4709 3.90476 20.0952 7.52912 20.0952 12H22Z" fill="var(--instrument-regular-secondary-color)"/>
82
- <path d="M12 22C17.5228 22 22 17.5228 22 12H20.0952C20.0952 16.4709 16.4709 20.0952 12 20.0952V22Z" fill="var(--instrument-regular-secondary-color)"/>
83
- <path d="M2 12C2 17.5228 6.47715 22 12 22V20.0952C7.52912 20.0952 3.90476 16.4709 3.90476 12H2Z" fill="var(--instrument-regular-secondary-color)"/>`,
84
- 'wind-2.svg': svg`<path d="M11 24H13L13 7H15L12 0L9 7H11L11 24Z" stroke="var(--border-silhouette-color)" stroke-width="2"/>
85
- <path d="M11 24H13L13 7H15L12 0L9 7H11L11 24Z" fill="var(--instrument-regular-secondary-color)"/>`,
86
- 'wind-3.svg': svg`<path d="M11 24L13 24L13 7L15 7L12 -1.74846e-07L9 7L11 7L11 24Z" stroke="var(--border-silhouette-color)" stroke-width="2"/>
87
- <path d="M8 21L8 19L11 19L11 21L8 21Z" stroke="var(--border-silhouette-color)" stroke-width="2"/>
88
- <path d="M11 24L13 24L13 7L15 7L12 -1.74846e-07L9 7L11 7L11 24Z" fill="var(--instrument-regular-secondary-color)"/>
89
- <path d="M8 21L8 19L11 19L11 21L8 21Z" fill="var(--instrument-regular-secondary-color)"/>`,
90
- 'wind-4.svg': svg`<path d="M11 24L13 24L13 7L15 7L12 -2.62268e-07L9 7L11 7L11 24Z" stroke="var(--border-silhouette-color)" stroke-width="2"/>
91
- <path d="M6 24L6 22L11 22L11 24L6 24Z" stroke="var(--border-silhouette-color)" stroke-width="2"/>
92
- <path d="M11 24L13 24L13 7L15 7L12 -2.62268e-07L9 7L11 7L11 24Z" fill="var(--instrument-regular-secondary-color)"/>
93
- <path d="M6 24L6 22L11 22L11 24L6 24Z" fill="var(--instrument-regular-secondary-color)"/>`,
94
- 'wind-5.svg': svg`<path d="M11 24H13L13 7H15L12 0L9 7H11L11 24Z" stroke="var(--border-silhouette-color)" stroke-width="2"/>
95
- <path d="M5 24L5 22H12V24H5Z" stroke="var(--border-silhouette-color)" stroke-width="2"/>
96
- <path d="M8 21L8 19H12V21H8Z" stroke="var(--border-silhouette-color)" stroke-width="2"/>
97
- <path d="M11 24H13L13 7H15L12 0L9 7H11L11 24Z" fill="var(--instrument-regular-secondary-color)"/>
98
- <path d="M5 24L5 22H12V24H5Z" fill="var(--instrument-regular-secondary-color)"/>
99
- <path d="M8 21L8 19H12V21H8Z" fill="var(--instrument-regular-secondary-color)"/>`,
100
- 'wind-6.svg': svg`<path d="M11 24H13L13 7L15 7L12 0L9 7H11L11 24Z" stroke="var(--border-silhouette-color)" stroke-width="2"/>
101
- <path d="M5 24L5 22H12V24H5Z" stroke="var(--border-silhouette-color)" stroke-width="2"/>
102
- <path d="M5 21L5 19H12V21H5Z" stroke="var(--border-silhouette-color)" stroke-width="2"/>
103
- <path d="M11 24H13L13 7L15 7L12 0L9 7H11L11 24Z" fill="var(--instrument-regular-secondary-color)"/>
104
- <path d="M5 24L5 22H12V24H5Z" fill="var(--instrument-regular-secondary-color)"/>
105
- <path d="M5 21L5 19H12V21H5Z" fill="var(--instrument-regular-secondary-color)"/>`,
106
- 'wind-7.svg': svg`<path d="M11 24H13L13 7H15L12 0L9 7H11L11 24Z" stroke="var(--border-silhouette-color)" stroke-width="2"/>
107
- <path d="M5 24L5 22H12V24H5Z" stroke="var(--border-silhouette-color)" stroke-width="2"/>
108
- <path d="M5 21L5 19H12V21H5Z" stroke="var(--border-silhouette-color)" stroke-width="2"/>
109
- <path d="M8 18L8 16H12V18H8Z" stroke="var(--border-silhouette-color)" stroke-width="2"/>
110
- <path d="M11 24H13L13 7H15L12 0L9 7H11L11 24Z" fill="var(--instrument-regular-secondary-color)"/>
111
- <path d="M5 24L5 22H12V24H5Z" fill="var(--instrument-regular-secondary-color)"/>
112
- <path d="M5 21L5 19H12V21H5Z" fill="var(--instrument-regular-secondary-color)"/>
113
- <path d="M8 18L8 16H12V18H8Z" fill="var(--instrument-regular-secondary-color)"/>`,
114
- 'wind-8.svg': svg`<path d="M11 24H13L13 7H15L12 0L9 7H11L11 24Z" stroke="var(--border-silhouette-color)" stroke-width="2"/>
115
- <path d="M5 24L5 22H12V24H5Z" stroke="var(--border-silhouette-color)" stroke-width="2"/>
116
- <path d="M5 21L5 19H12V21H5Z" stroke="var(--border-silhouette-color)" stroke-width="2"/>
117
- <path d="M5 18L5 16H12V18H5Z" stroke="var(--border-silhouette-color)" stroke-width="2"/>
118
- <path d="M11 24H13L13 7H15L12 0L9 7H11L11 24Z" fill="var(--instrument-regular-secondary-color)"/>
119
- <path d="M5 24L5 22H12V24H5Z" fill="var(--instrument-regular-secondary-color)"/>
120
- <path d="M5 21L5 19H12V21H5Z" fill="var(--instrument-regular-secondary-color)"/>
121
- <path d="M5 18L5 16H12V18H5Z" fill="var(--instrument-regular-secondary-color)"/>`,
122
- 'wind-9.svg': svg`<path d="M11 24H13L13 7H15L12 0L9 7H11L11 24Z" stroke="var(--border-silhouette-color)" stroke-width="2"/>
123
- <path d="M5 24L5 22H12V24H5Z" stroke="var(--border-silhouette-color)" stroke-width="2"/>
124
- <path d="M5 21L5 19H12V21H5Z" stroke="var(--border-silhouette-color)" stroke-width="2"/>
125
- <path d="M5 18L5 16H12V18H5Z" stroke="var(--border-silhouette-color)" stroke-width="2"/>
126
- <path d="M8 15L8 13H12V15H5Z" stroke="var(--border-silhouette-color)" stroke-width="2"/>
127
- <path d="M11 24H13L13 7H15L12 0L9 7H11L11 24Z" fill="var(--instrument-regular-secondary-color)"/>
128
- <path d="M5 24L5 22H12V24H5Z" fill="var(--instrument-regular-secondary-color)"/>
129
- <path d="M5 21L5 19H12V21H5Z" fill="var(--instrument-regular-secondary-color)"/>
130
- <path d="M5 18L5 16H12V18H5Z" fill="var(--instrument-regular-secondary-color)"/>
131
- <path d="M8 15L8 13H12V15H5Z" fill="var(--instrument-regular-secondary-color)"/>`,
132
- 'wind-10.svg': svg`<path d="M11 24H13L13 7H15L12 0L9 7H11L11 24Z" stroke="var(--border-silhouette-color)" stroke-width="2"/>
133
- <path d="M5 24L5 22H12V24H5Z" stroke="var(--border-silhouette-color)" stroke-width="2"/>
134
- <path d="M5 21L5 19H12V21H5Z" stroke="var(--border-silhouette-color)" stroke-width="2"/>
135
- <path d="M5 18L5 16H12V18H5Z" stroke="var(--border-silhouette-color)" stroke-width="2"/>
136
- <path d="M5 15L5 13H12V15H5Z" stroke="var(--border-silhouette-color)" stroke-width="2"/>
137
- <path d="M8 12L8 10H12V12H8Z" stroke="var(--border-silhouette-color)" stroke-width="2"/>
138
- <path d="M11 24H13L13 7H15L12 0L9 7H11L11 24Z" fill="var(--instrument-regular-secondary-color)"/>
139
- <path d="M5 24L5 22H12V24H5Z" fill="var(--instrument-regular-secondary-color)"/>
140
- <path d="M5 21L5 19H12V21H5Z" fill="var(--instrument-regular-secondary-color)"/>
141
- <path d="M5 18L5 16H12V18H5Z" fill="var(--instrument-regular-secondary-color)"/>
142
- <path d="M5 15L5 13H12V15H5Z" fill="var(--instrument-regular-secondary-color)"/>
143
- <path d="M8 12L8 10H12V12H8Z" fill="var(--instrument-regular-secondary-color)"/>`,
144
- 'wind-11.svg': svg`<path d="M5 22L13 24L13 7H15L12 0L9 7H11L11 20L5 22Z" stroke="var(--border-silhouette-color)" stroke-width="2"/>
145
- <path d="M5 22L13 24L13 7H15L12 0L9 7H11L11 20L5 22Z" fill="var(--instrument-regular-secondary-color)"/>`,
146
- 'wind-12.svg': svg`<path d="M5 22L13 24L13 7H15L12 0L9 7H11L11 19L5 22Z" stroke="var(--border-silhouette-color)" stroke-width="2"/>
147
- <path d="M5 18L5 16H12V18H5Z" stroke="var(--border-silhouette-color)" stroke-width="2"/>
148
- <path d="M5 22L13 24L13 7H15L12 0L9 7H11L11 19L5 22Z" fill="var(--instrument-regular-secondary-color)"/>
149
- <path d="M5 18L5 16H12V18H5Z" fill="var(--instrument-regular-secondary-color)"/>`,
150
- 'wind-13.svg': svg`<path d="M5 22L13 24L13 7H15L12 0L9 7H11L11 19L5 22Z" stroke="var(--border-silhouette-color)" stroke-width="2"/>
151
- <path d="M5 18L5 16H12V18H5Z" stroke="var(--border-silhouette-color)" stroke-width="2"/>
152
- <path d="M5 15L5 13H12V15H5Z" stroke="var(--border-silhouette-color)" stroke-width="2"/>
153
- <path d="M5 22L13 24L13 7H15L12 0L9 7H11L11 19L5 22Z" fill="var(--instrument-regular-secondary-color)"/>
154
- <path d="M5 18L5 16H12V18H5Z" fill="var(--instrument-regular-secondary-color)"/>
155
- <path d="M5 15L5 13H12V15H5Z" fill="var(--instrument-regular-secondary-color)"/>`,
156
189
  };
@@ -71,7 +71,7 @@ Source of truth: \`packages/openbridge-webcomponents/src/navigation-instruments/
71
71
  areas: {control: {type: 'object'}},
72
72
  padding: {control: {type: 'range', min: 0, max: 100, step: 1}},
73
73
  vessels: {control: {type: 'object'}},
74
- wind: {control: {type: 'range', min: 0, max: 12, step: 1}},
74
+ windKnots: {control: {type: 'range', min: 0, max: 70, step: 1}},
75
75
  windFromDirectionDeg: {control: {type: 'range', min: 0, max: 360, step: 1}},
76
76
  windSymbolRadius: {control: {type: 'range', min: 0, max: 360, step: 1}},
77
77
  current: {control: {type: 'range', min: 0, max: 4, step: 1}},
@@ -194,7 +194,7 @@ export const WithStarboardPortIndicator: Story = {
194
194
 
195
195
  export const WithWind: Story = {
196
196
  args: {
197
- wind: 10,
197
+ windKnots: 50,
198
198
  windFromDirectionDeg: 116,
199
199
  padding: 70,
200
200
  windSymbolRadius: 190,
@@ -222,7 +222,7 @@ export class ObcWatch extends LitElement {
222
222
  @property({type: Boolean}) crosshairEnabled: boolean = false;
223
223
  @property({type: Boolean}) showLabels: boolean = false;
224
224
  @property({type: Array, attribute: false}) vessels: WatchVessel[] = [];
225
- @property({type: Number}) wind: number | null = null;
225
+ @property({type: Number}) windKnots: number | null = null;
226
226
  @property({type: Number}) windFromDirectionDeg: number | null = null;
227
227
  @property({type: Number}) windSymbolRadius: number | null = null;
228
228
  @property({type: String}) windColor: string | undefined;
@@ -766,9 +766,9 @@ export class ObcWatch extends LitElement {
766
766
  })
767
767
  : nothing;
768
768
  const wind =
769
- this.wind != null && this.windFromDirectionDeg != null
769
+ this.windKnots != null && this.windFromDirectionDeg != null
770
770
  ? svg`<g transform="scale(${this.scaleWindIcon})">${renderWind({
771
- wind: this.wind,
771
+ windKnots: this.windKnots,
772
772
  fromDirectionDeg: this.windFromDirectionDeg,
773
773
  radius: this.windSymbolRadius ?? 192,
774
774
  color: this.windColor,
@@ -76,7 +76,7 @@ const meta: Meta<typeof ObcWind> = {
76
76
  width: 400,
77
77
  vesselHeadingDeg: 60,
78
78
  currentWindFromDirection: 100,
79
- currentWindSpeedBeaufort: 5,
79
+ currentWindSpeedKnots: 25,
80
80
  windHistogramData: windHistogramData,
81
81
  },
82
82
  argTypes: {
@@ -85,8 +85,9 @@ const meta: Meta<typeof ObcWind> = {
85
85
  currentWindFromDirection: {
86
86
  control: {type: 'range', min: 0, max: 360, step: 1},
87
87
  },
88
- currentWindSpeedBeaufort: {
89
- control: {type: 'range', min: 0, max: 12, step: 1},
88
+ currentWindSpeedKnots: {
89
+ control: {type: 'range', min: 0, max: 75, step: 1},
90
+ description: 'Wind speed in knots.',
90
91
  },
91
92
  windHistogramData: {control: 'object'},
92
93
  vesselImage: {
@@ -33,7 +33,7 @@ const WIND_HISTOGRAM_MIN_RADIUS = 50;
33
33
  @customElement('obc-wind')
34
34
  export class ObcWind extends LitElement {
35
35
  @property({type: Number}) currentWindFromDirection: number = 0;
36
- @property({type: Number}) currentWindSpeedBeaufort: number = 1;
36
+ @property({type: Number}) currentWindSpeedKnots: number = 25;
37
37
  @property({type: Array, attribute: false})
38
38
  windHistogramData: WindHistogramData[] = [];
39
39
  @property({type: String}) vesselImage: VesselImage = VesselImage.genericTop;
@@ -146,7 +146,7 @@ export class ObcWind extends LitElement {
146
146
  ${this.renderWindHistogram(variant)}
147
147
  <obc-watch
148
148
  .watchCircleType=${watchCircleType}
149
- .wind=${this.currentWindSpeedBeaufort}
149
+ .windKnots=${this.currentWindSpeedKnots}
150
150
  .windFromDirectionDeg=${this.currentWindFromDirection}
151
151
  .windSymbolRadius=${windSymbolRadius}
152
152
  .scaleWindIcon=${scaleWindIcon}
@@ -11,15 +11,18 @@ type WindIndicatorArgs = {
11
11
  type: WindIndicatorType;
12
12
  direction: WindIndicatorDirection;
13
13
  priority: WindIndicatorPriority;
14
- level: number;
14
+ currentWindSpeedKnots: number;
15
15
  rotationAngle: number;
16
- windFromAngle: number;
16
+ currentWindFromDirection: number;
17
17
  angle?: number;
18
18
  'wind-from-angle'?: number;
19
+ 'current-wind-from-direction'?: number;
19
20
  'rotation-angle'?: number;
20
- clampedLevel?: number;
21
+ 'current-wind-speed-knots'?: number;
22
+ iconIndex?: number;
21
23
  accentColor?: string;
22
24
  windIconCache?: unknown;
25
+ windFromAngle?: number;
23
26
  };
24
27
 
25
28
  const meta: Meta<WindIndicatorArgs> = {
@@ -37,14 +40,14 @@ const meta: Meta<WindIndicatorArgs> = {
37
40
  .type=${args.type}
38
41
  .direction=${args.direction}
39
42
  .priority=${args.priority}
40
- .level=${args.level}
43
+ .currentWindSpeedKnots=${args.currentWindSpeedKnots}
41
44
  .rotationAngle=${args.rotationAngle}
42
- .windFromAngle=${args.windFromAngle}
45
+ .currentWindFromDirection=${args.currentWindFromDirection}
43
46
  ></obc-wind-indicator>
44
47
  `,
45
48
  args: {
46
- windFromAngle: 0,
47
- level: 7,
49
+ currentWindFromDirection: 0,
50
+ currentWindSpeedKnots: 35,
48
51
  type: WindIndicatorType.arrow,
49
52
  direction: WindIndicatorDirection.true,
50
53
  priority: WindIndicatorPriority.regular,
@@ -59,8 +62,8 @@ const meta: Meta<WindIndicatorArgs> = {
59
62
  control: {type: 'select'},
60
63
  options: Object.values(WindIndicatorDirection),
61
64
  },
62
- windFromAngle: {
63
- name: 'Wind From Angle',
65
+ currentWindFromDirection: {
66
+ name: 'Current Wind From Direction',
64
67
  description: 'Wind-from angle in degrees. 0/360 = wind from north.',
65
68
  control: {type: 'range', min: 0, max: 360, step: 1},
66
69
  },
@@ -74,12 +77,19 @@ const meta: Meta<WindIndicatorArgs> = {
74
77
  control: {type: 'select'},
75
78
  options: Object.values(WindIndicatorPriority),
76
79
  },
77
- level: {control: {type: 'range', min: 0, max: 12, step: 1}},
80
+ currentWindSpeedKnots: {
81
+ description:
82
+ 'Wind speed in knots. Mapped to barb icons in 5-kn steps (standard meteorological wind-barb convention).',
83
+ control: {type: 'range', min: 0, max: 75, step: 1},
84
+ },
78
85
 
79
86
  angle: {table: {disable: true}, control: false},
87
+ windFromAngle: {table: {disable: true}, control: false},
80
88
  'wind-from-angle': {table: {disable: true}, control: false},
89
+ 'current-wind-from-direction': {table: {disable: true}, control: false},
81
90
  'rotation-angle': {table: {disable: true}, control: false},
82
- clampedLevel: {table: {disable: true}, control: false},
91
+ 'current-wind-speed-knots': {table: {disable: true}, control: false},
92
+ iconIndex: {table: {disable: true}, control: false},
83
93
  accentColor: {table: {disable: true}, control: false},
84
94
  windIconCache: {table: {disable: true}, control: false},
85
95
  },
@@ -121,6 +131,6 @@ export const Labeled: Story = {
121
131
  type: WindIndicatorType.labeled,
122
132
  direction: WindIndicatorDirection.true,
123
133
  priority: WindIndicatorPriority.regular,
124
- level: 12,
134
+ currentWindSpeedKnots: 60,
125
135
  },
126
136
  };
@@ -2,7 +2,35 @@ import {LitElement, css, html, svg, type SVGTemplateResult} from 'lit';
2
2
  import {property} from 'lit/decorators.js';
3
3
  import {customElement} from '../../decorator.js';
4
4
  import {styleMap} from 'lit/directives/style-map.js';
5
- import '../../icons/index.js';
5
+ import '../../icons/icon-wind-true-1.js';
6
+ import '../../icons/icon-wind-true-2.js';
7
+ import '../../icons/icon-wind-true-3.js';
8
+ import '../../icons/icon-wind-true-4.js';
9
+ import '../../icons/icon-wind-true-5.js';
10
+ import '../../icons/icon-wind-true-6.js';
11
+ import '../../icons/icon-wind-true-7.js';
12
+ import '../../icons/icon-wind-true-8.js';
13
+ import '../../icons/icon-wind-true-9.js';
14
+ import '../../icons/icon-wind-true-10.js';
15
+ import '../../icons/icon-wind-true-11.js';
16
+ import '../../icons/icon-wind-true-12.js';
17
+ import '../../icons/icon-wind-true-13.js';
18
+ import '../../icons/icon-wind-true-14.js';
19
+ import '../../icons/icon-wind-shaft-1.js';
20
+ import '../../icons/icon-wind-shaft-2.js';
21
+ import '../../icons/icon-wind-shaft-3.js';
22
+ import '../../icons/icon-wind-shaft-4.js';
23
+ import '../../icons/icon-wind-shaft-5.js';
24
+ import '../../icons/icon-wind-shaft-6.js';
25
+ import '../../icons/icon-wind-shaft-7.js';
26
+ import '../../icons/icon-wind-shaft-8.js';
27
+ import '../../icons/icon-wind-shaft-9.js';
28
+ import '../../icons/icon-wind-shaft-10.js';
29
+ import '../../icons/icon-wind-shaft-11.js';
30
+ import '../../icons/icon-wind-shaft-12.js';
31
+ import '../../icons/icon-wind-shaft-13.js';
32
+ import '../../icons/icon-wind-shaft-14.js';
33
+ import {windKnotsToIconIndex} from '../watch/environment.js';
6
34
 
7
35
  export enum WindIndicatorType {
8
36
  arrow = 'arrow',
@@ -43,13 +71,6 @@ const SHAFT_TRUE_CIRCLE_TPL = svg`
43
71
  />
44
72
  `;
45
73
 
46
- const SHAFT_TRUE_WIND_BARB_TPL = svg`
47
- <path
48
- d="M39.613 20.3747C39.7971 20.6935 39.6878 21.1013 39.3689 21.2853C39.0501 21.4694 38.6424 21.3602 38.4583 21.0413L36.4583 17.5772L35.3036 18.2439L37.3036 21.708C37.4876 22.0269 37.3784 22.4346 37.0595 22.6187C36.7407 22.8028 36.3329 22.6935 36.1489 22.3747L34.1489 18.9106L32.9942 19.5772L33.9942 21.3093C34.1782 21.6281 34.069 22.0359 33.7501 22.22C33.4313 22.4041 33.0235 22.2948 32.8395 21.9759L31.8395 20.2439L24.3339 24.5772L23.6672 23.4225L36.3114 16.1224C36.6621 15.9201 37.1103 16.0402 37.3128 16.3907L39.613 20.3747Z"
49
- fill="currentColor"
50
- />
51
- `;
52
-
53
74
  const SHAFT_TRUE_WIND_BARB_D_BY_LEVEL: string[] = [
54
75
  'M33.0954 23.7527C35.1680 22.5560 35.8782 19.9058 34.6816 17.8332C33.4850 15.7606 30.8347 15.0504 28.7621 16.2471C26.6895 17.4437 25.9794 20.0939 27.1760 22.1665L26.3099 22.6665C24.8372 20.1156 25.7112 16.8538 28.2621 15.3810C30.8130 13.9083 34.0748 14.7823 35.5476 17.3332C37.0204 19.8841 36.1463 23.1459 33.5954 24.6187C31.0445 26.0914 27.7827 25.2174 26.3099 22.6665L27.1760 22.1665C28.3726 24.2392 31.0228 24.9493 33.0954 23.7527L33.0954 23.7527',
55
76
  'M37.2797 16.3332C37.4638 16.6521 37.3545 17.0598 37.0356 17.2439L24.3339 24.5772L23.6672 23.4225L36.3690 16.0892C36.6878 15.9051 37.0956 16.0143 37.2797 16.3332L37.2797 16.3332',
@@ -64,6 +85,7 @@ const SHAFT_TRUE_WIND_BARB_D_BY_LEVEL: string[] = [
64
85
  'M39.6130 20.3747C39.7971 20.6936 39.6878 21.1013 39.3690 21.2854C39.0501 21.4695 38.6424 21.3602 38.4583 21.0413L36.4583 17.5772L35.3036 18.2439L37.3036 21.7080C37.4877 22.0269 37.3784 22.4346 37.0595 22.6187C36.7407 22.8028 36.3330 22.6935 36.1489 22.3747L34.1489 18.9106L32.9942 19.5772L34.9941 23.0413C35.1782 23.3602 35.0690 23.7679 34.7501 23.9520C34.4313 24.1361 34.0235 24.0269 33.8394 23.7080L31.8395 20.2439L30.6847 20.9105L32.6847 24.3747C32.8688 24.6935 32.7596 25.1012 32.4407 25.2853C32.1218 25.4694 31.7141 25.3602 31.5300 25.0413L29.5300 21.5772L28.3753 22.2439L29.3753 23.9759C29.5594 24.2948 29.4502 24.7025 29.1313 24.8866C28.8124 25.0707 28.4047 24.9615 28.2206 24.6426L27.2206 22.9105L24.3339 24.5772L23.6672 23.4225L36.3115 16.1224C36.6621 15.9201 37.1103 16.0402 37.3129 16.3907L39.6130 20.3747L39.6130 20.3747',
65
86
  'M37.3380 16.4822L37.3672 16.5654L38.7821 21.5122C38.9920 22.2462 38.0802 22.7726 37.5496 22.2238L34.2758 18.8373L24.3339 24.5772L23.6672 23.4224L36.2952 16.1318C36.6825 15.9082 37.1705 16.0816 37.3380 16.4822L37.3380 16.4822',
66
87
  'M37.3380 16.4822L37.3672 16.5654L38.7821 21.5122C38.9920 22.2462 38.0802 22.7726 37.5496 22.2238L34.2758 18.8373L32.9942 19.5772L34.9942 23.0413C35.1783 23.3602 35.0690 23.7679 34.7502 23.9520C34.4313 24.1361 34.0236 24.0268 33.8395 23.7080L31.8395 20.2438L24.3339 24.5772L23.6672 23.4224L36.2952 16.1318C36.6825 15.9082 37.1705 16.0816 37.3380 16.4822L37.3380 16.4822',
88
+ 'M37.3380 16.4822L37.3672 16.5654L38.7821 21.5122C38.9920 22.2462 38.0802 22.7726 37.5496 22.2238L34.2758 18.8373L32.9942 19.5772L34.9942 23.0413C35.1783 23.3602 35.0690 23.7679 34.7502 23.9520C34.4313 24.1361 34.0236 24.0268 33.8395 23.7080L31.8395 20.2438L30.6847 20.9105L32.6847 24.3747C32.8688 24.6935 32.7596 25.1012 32.4407 25.2853C32.1218 25.4694 31.7141 25.3602 31.5300 25.0413L29.5300 21.5772L24.3339 24.5772L23.6672 23.4224L36.2952 16.1318C36.6825 15.9082 37.1705 16.0816 37.3380 16.4822L37.3380 16.4822',
67
89
  ];
68
90
 
69
91
  const SHAFT_RELATIVE_EXPORT_OFFSET_X = -9.9395;
@@ -169,16 +191,23 @@ const LABELED_ARROW_TPL = svg`
169
191
  /**
170
192
  * `<obc-wind-indicator>` – A compact wind indicator with a fixed frame and a rotating wind marker.
171
193
  *
172
- * Visualizes a discrete wind `level` using a compact icon plus optional mode layers.
194
+ * Visualizes a wind speed in knots using a compact wind-barb icon plus
195
+ * optional mode layers.
173
196
  *
174
197
  * ## Features
175
198
  *
176
199
  * - **Variants:** `type` (`arrow` | `shaft` | `labeled`), `direction` (`true` | `relative`), `priority` (`regular` | `enhanced`).
177
- * - **Discrete input:** `level` selects the icon state; mapping from real wind to `level` happens outside.
200
+ * - **Speed input:** `currentWindSpeedKnots` is the wind speed in knots.
201
+ * The barb icon follows the standard meteorological convention (one
202
+ * half-barb per 5 kn). 0–65 kn covers all 14 icons; higher values clamp
203
+ * to the heaviest icon.
178
204
  *
179
205
  * ## Usage Guidelines
180
206
  *
181
207
  * Use when you need a small wind cue next to other compact indicators.
208
+ * Pass the wind speed in knots through `currentWindSpeedKnots`, matching
209
+ * the convention used by `<obc-wind>`, `<obc-wind-propulsion>` and
210
+ * `<obc-compass>`.
182
211
  */
183
212
  @customElement('obc-wind-indicator')
184
213
  export class ObcWindIndicator extends LitElement {
@@ -190,12 +219,24 @@ export class ObcWindIndicator extends LitElement {
190
219
  @property({type: String}) priority: WindIndicatorPriority =
191
220
  WindIndicatorPriority.regular;
192
221
 
193
- @property({type: Number}) level = 0;
222
+ /**
223
+ * Wind speed in **knots**, used to pick the wind-barb icon.
224
+ *
225
+ * Maps to the icon set using the designer-confirmed "Option C"
226
+ * ranges: `[0, 0.5)` kn renders calm, `[0.5, 2.5)` kn renders a
227
+ * shaft only, then 5-kn nearest-neighbour buckets up to 45 kn
228
+ * (half-barb steps), `[47.5, 55)` kn renders the 50-kn pennant, and
229
+ * `[55, 65)` / `[65, ∞)` kn add one and two full barbs above the
230
+ * pennant respectively. Non-finite or negative values fall back to
231
+ * calm.
232
+ */
233
+ @property({type: Number, attribute: 'current-wind-speed-knots'})
234
+ currentWindSpeedKnots = 0;
194
235
 
195
236
  /**
196
237
  * Rotation of the reference frame (course/heading) in degrees.
197
238
  *
198
- * Used in relative mode to compute the marker rotation as `windFromAngle - rotationAngle`.
239
+ * This could be the heading or the course of the vessel.
199
240
  * `0` means north-up.
200
241
  */
201
242
  @property({type: Number, attribute: 'rotation-angle'}) rotationAngle = 0;
@@ -207,17 +248,29 @@ export class ObcWindIndicator extends LitElement {
207
248
  * - `0` / `360`: wind from north → marker points south (down)
208
249
  * - `180`: wind from south → marker points north (up)
209
250
  */
210
- @property({type: Number, attribute: 'wind-from-angle'}) windFromAngle = 0;
251
+ @property({type: Number, attribute: 'current-wind-from-direction'})
252
+ currentWindFromDirection = 0;
211
253
 
212
254
  /**
213
- * @deprecated Use `windFromAngle` instead.
255
+ * @deprecated Use `currentWindFromDirection` instead.
256
+ */
257
+ @property({type: Number})
258
+ get windFromAngle() {
259
+ return this.currentWindFromDirection;
260
+ }
261
+ set windFromAngle(value: number) {
262
+ this.currentWindFromDirection = value;
263
+ }
264
+
265
+ /**
266
+ * @deprecated Use `currentWindFromDirection` instead.
214
267
  */
215
268
  @property({type: Number})
216
269
  get angle() {
217
- return this.windFromAngle;
270
+ return this.currentWindFromDirection;
218
271
  }
219
272
  set angle(value: number) {
220
- this.windFromAngle = value;
273
+ this.currentWindFromDirection = value;
221
274
  }
222
275
 
223
276
  static override styles = css`
@@ -252,15 +305,13 @@ export class ObcWindIndicator extends LitElement {
252
305
  }
253
306
  `;
254
307
 
255
- private clampLevel(value: number): number {
256
- if (!Number.isFinite(value)) {
257
- return 0;
258
- }
259
- return Math.max(0, Math.min(12, Math.round(value)));
260
- }
261
-
262
- private get clampedLevel(): number {
263
- return this.clampLevel(this.level);
308
+ /**
309
+ * Icon index in the range `1..14`, derived from `currentWindSpeedKnots`
310
+ * via the shared `windKnotsToIconIndex` helper (standard meteorological
311
+ * wind-barb convention; one half-barb per 5 kn).
312
+ */
313
+ private get iconIndex(): number {
314
+ return windKnotsToIconIndex(this.currentWindSpeedKnots);
264
315
  }
265
316
 
266
317
  private get accentColor(): string {
@@ -271,11 +322,11 @@ export class ObcWindIndicator extends LitElement {
271
322
 
272
323
  private getWindBaseAngle(): number {
273
324
  if (this.type === WindIndicatorType.labeled) {
274
- return this.windFromAngle;
325
+ return this.currentWindFromDirection;
275
326
  }
276
327
  return this.direction === WindIndicatorDirection.relative
277
- ? this.windFromAngle - this.rotationAngle
278
- : this.windFromAngle;
328
+ ? this.currentWindFromDirection + this.rotationAngle
329
+ : this.currentWindFromDirection;
279
330
  }
280
331
 
281
332
  private getWindRotation(offsetDeg = 0): number {
@@ -309,12 +360,8 @@ export class ObcWindIndicator extends LitElement {
309
360
  return tpl;
310
361
  }
311
362
 
312
- private getWindIconTagName(
313
- type: string,
314
- _direction: string,
315
- level: number
316
- ): string {
317
- const index = Math.max(0, Math.min(12, Math.round(level))) + 1;
363
+ private getWindIconTagName(type: string, _direction: string): string {
364
+ const index = this.iconIndex;
318
365
 
319
366
  if (type === WindIndicatorType.shaft) {
320
367
  return `obi-wind-shaft-${index}`;
@@ -325,10 +372,9 @@ export class ObcWindIndicator extends LitElement {
325
372
 
326
373
  private getWindIcon(
327
374
  type: string,
328
- direction: string,
329
- level: number
375
+ direction: string
330
376
  ): SVGTemplateResult | null {
331
- const tagName = this.getWindIconTagName(type, direction, level);
377
+ const tagName = this.getWindIconTagName(type, direction);
332
378
  return this.getWindIconSvg(tagName);
333
379
  }
334
380
 
@@ -412,8 +458,7 @@ export class ObcWindIndicator extends LitElement {
412
458
  const windStyles = {color: this.accentColor};
413
459
  const windIcon = this.getWindIcon(
414
460
  WindIndicatorType.shaft,
415
- this.direction,
416
- this.clampedLevel
461
+ this.direction
417
462
  );
418
463
 
419
464
  const windMarker = svg`
@@ -473,17 +518,13 @@ export class ObcWindIndicator extends LitElement {
473
518
  transform="rotate(${this.getWindRotation(SHAFT_TRUE_ARROW_OFFSET_DEG)} ${CX} ${CY})"
474
519
  data-name="hdg"
475
520
  >
476
- ${
477
- this.clampedLevel === 7
478
- ? SHAFT_TRUE_WIND_BARB_TPL
479
- : svg`<path d=${SHAFT_TRUE_WIND_BARB_D_BY_LEVEL[this.clampedLevel]} fill="currentColor" />`
480
- }
521
+ ${svg`<path d=${SHAFT_TRUE_WIND_BARB_D_BY_LEVEL[this.iconIndex - 1]} fill="currentColor" />`}
481
522
  ${SHAFT_TRUE_CIRCLE_TPL}
482
523
  </g>
483
524
  `;
484
525
  }
485
526
 
486
- const icon = this.getWindIcon(this.type, this.direction, this.clampedLevel);
527
+ const icon = this.getWindIcon(this.type, this.direction);
487
528
  if (!icon) {
488
529
  return null;
489
530
  }
@@ -505,6 +546,10 @@ export class ObcWindIndicator extends LitElement {
505
546
  return null;
506
547
  }
507
548
 
549
+ const value = Number.isFinite(this.currentWindSpeedKnots)
550
+ ? Math.max(0, Math.round(this.currentWindSpeedKnots))
551
+ : 0;
552
+
508
553
  return svg`
509
554
  <text
510
555
  x="${CX}"
@@ -516,7 +561,7 @@ export class ObcWindIndicator extends LitElement {
516
561
  font-weight="var(--global-typography-ui-label-active-font-weight)"
517
562
  line-height="var(--global-typography-ui-label-active-line-height)"
518
563
  >
519
- ${this.clampedLevel}
564
+ ${value}
520
565
  </text>
521
566
  `;
522
567
  }