@oicl/openbridge-webcomponents-full-bundle 2.0.0-next.111 → 2.0.0-next.113
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 +185 -29
- package/bundle/openbridge-webcomponents.bundle.js.map +1 -1
- package/custom-elements.json +180 -21
- package/dist/building-blocks/readout-block/readout-block.d.ts +29 -5
- package/dist/building-blocks/readout-block/readout-block.d.ts.map +1 -1
- package/dist/building-blocks/readout-block/readout-block.js +21 -7
- package/dist/building-blocks/readout-block/readout-block.js.map +1 -1
- package/dist/navigation-instruments/compass/compass.d.ts +1 -1
- package/dist/navigation-instruments/compass/compass.d.ts.map +1 -1
- package/dist/navigation-instruments/compass/compass.js +1 -1
- package/dist/navigation-instruments/compass/compass.js.map +1 -1
- package/dist/navigation-instruments/current/current.d.ts +25 -0
- package/dist/navigation-instruments/current/current.d.ts.map +1 -1
- package/dist/navigation-instruments/current/current.js +25 -4
- package/dist/navigation-instruments/current/current.js.map +1 -1
- package/dist/navigation-instruments/heading/heading.js +1 -1
- package/dist/navigation-instruments/heading/heading.js.map +1 -1
- package/dist/navigation-instruments/pitch-roll-heave/pitch-roll-heave.d.ts +6 -0
- package/dist/navigation-instruments/pitch-roll-heave/pitch-roll-heave.d.ts.map +1 -1
- package/dist/navigation-instruments/pitch-roll-heave/pitch-roll-heave.js +8 -1
- package/dist/navigation-instruments/pitch-roll-heave/pitch-roll-heave.js.map +1 -1
- package/dist/navigation-instruments/rate-of-turn/rate-of-turn.d.ts +5 -2
- package/dist/navigation-instruments/rate-of-turn/rate-of-turn.d.ts.map +1 -1
- package/dist/navigation-instruments/rate-of-turn/rate-of-turn.js.map +1 -1
- package/dist/navigation-instruments/readout/readout-formatters.d.ts +31 -0
- package/dist/navigation-instruments/readout/readout-formatters.d.ts.map +1 -1
- package/dist/navigation-instruments/readout/readout-formatters.js +55 -1
- package/dist/navigation-instruments/readout/readout-formatters.js.map +1 -1
- package/dist/navigation-instruments/readout/readout.d.ts +26 -1
- package/dist/navigation-instruments/readout/readout.d.ts.map +1 -1
- package/dist/navigation-instruments/readout/readout.js +16 -3
- package/dist/navigation-instruments/readout/readout.js.map +1 -1
- package/dist/navigation-instruments/readout-list/readout-list.d.ts +6 -1
- package/dist/navigation-instruments/readout-list/readout-list.d.ts.map +1 -1
- package/dist/navigation-instruments/readout-list/readout-list.js +21 -4
- package/dist/navigation-instruments/readout-list/readout-list.js.map +1 -1
- package/dist/navigation-instruments/readout-list-item/readout-list-item.d.ts +26 -1
- package/dist/navigation-instruments/readout-list-item/readout-list-item.d.ts.map +1 -1
- package/dist/navigation-instruments/readout-list-item/readout-list-item.js +15 -3
- package/dist/navigation-instruments/readout-list-item/readout-list-item.js.map +1 -1
- package/dist/navigation-instruments/top-view-propulsion/top-view-propulsion.d.ts +6 -0
- package/dist/navigation-instruments/top-view-propulsion/top-view-propulsion.d.ts.map +1 -1
- package/dist/navigation-instruments/top-view-propulsion/top-view-propulsion.js +19 -4
- package/dist/navigation-instruments/top-view-propulsion/top-view-propulsion.js.map +1 -1
- package/dist/navigation-instruments/watch/environment.d.ts +8 -0
- package/dist/navigation-instruments/watch/environment.d.ts.map +1 -1
- package/dist/navigation-instruments/watch/environment.js +3 -0
- package/dist/navigation-instruments/watch/environment.js.map +1 -1
- package/dist/navigation-instruments/watch/force-pattern.d.ts +20 -2
- package/dist/navigation-instruments/watch/force-pattern.d.ts.map +1 -1
- package/dist/navigation-instruments/watch/force-pattern.js +12 -5
- package/dist/navigation-instruments/watch/force-pattern.js.map +1 -1
- package/dist/navigation-instruments/watch/watch.d.ts.map +1 -1
- package/dist/navigation-instruments/watch/watch.js +6 -4
- package/dist/navigation-instruments/watch/watch.js.map +1 -1
- package/dist/navigation-instruments/wind/wind.d.ts +5 -2
- package/dist/navigation-instruments/wind/wind.d.ts.map +1 -1
- package/dist/navigation-instruments/wind/wind.js +5 -1
- package/dist/navigation-instruments/wind/wind.js.map +1 -1
- package/package.json +1 -1
- package/src/building-blocks/readout-block/readout-block.stories.ts +112 -3
- package/src/building-blocks/readout-block/readout-block.ts +64 -10
- package/src/navigation-instruments/compass/compass.ts +2 -2
- package/src/navigation-instruments/current/current.stories.ts +33 -0
- package/src/navigation-instruments/current/current.ts +37 -3
- package/src/navigation-instruments/heading/heading.stories.ts +6 -4
- package/src/navigation-instruments/heading/heading.ts +1 -1
- package/src/navigation-instruments/pitch-roll-heave/pitch-roll-heave.ts +8 -1
- package/src/navigation-instruments/rate-of-turn/rate-of-turn.stories.ts +3 -3
- package/src/navigation-instruments/rate-of-turn/rate-of-turn.ts +5 -2
- package/src/navigation-instruments/readout/readout-formatters.spec.ts +229 -0
- package/src/navigation-instruments/readout/readout-formatters.ts +105 -0
- package/src/navigation-instruments/readout/readout.stories.ts +167 -3
- package/src/navigation-instruments/readout/readout.ts +52 -4
- package/src/navigation-instruments/readout-list/readout-list.stories.ts +122 -1
- package/src/navigation-instruments/readout-list/readout-list.ts +54 -5
- package/src/navigation-instruments/readout-list-item/readout-list-item.stories.ts +124 -4
- package/src/navigation-instruments/readout-list-item/readout-list-item.ts +53 -4
- package/src/navigation-instruments/top-view-propulsion/top-view-propulsion.ts +20 -2
- package/src/navigation-instruments/watch/environment.ts +10 -0
- package/src/navigation-instruments/watch/force-pattern.spec.ts +42 -0
- package/src/navigation-instruments/watch/force-pattern.ts +44 -7
- package/src/navigation-instruments/watch/watch.ts +20 -5
- package/src/navigation-instruments/wind/wind.spec.ts +3 -1
- package/src/navigation-instruments/wind/wind.ts +12 -3
|
@@ -96,4 +96,46 @@ describe('renderCurrentForcePattern', () => {
|
|
|
96
96
|
);
|
|
97
97
|
expect(flat).toContain(String(-(256 * 1.39) / 2 + 104 * 1.39));
|
|
98
98
|
});
|
|
99
|
+
|
|
100
|
+
it('honors wave tuning: length scales the tile, height caps opacity, speed drifts', () => {
|
|
101
|
+
const flat = flatten(
|
|
102
|
+
renderCurrentForcePattern({
|
|
103
|
+
fromDirectionDeg: 0,
|
|
104
|
+
radius: 112,
|
|
105
|
+
patternScale: 2.0,
|
|
106
|
+
waveLength: 0.75,
|
|
107
|
+
waveHeight: 0.6,
|
|
108
|
+
waveSpeed: 0.4,
|
|
109
|
+
})
|
|
110
|
+
);
|
|
111
|
+
expect(flat).toContain(`width=${48 * 2.0 * 0.75}`);
|
|
112
|
+
expect(flat).toContain('stop-opacity=0.6');
|
|
113
|
+
expect(flat).toContain('animateTransform');
|
|
114
|
+
expect(flat).toContain('dur="2.5s"');
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
it('is static at full intensity without wave options', () => {
|
|
118
|
+
const flat = flatten(
|
|
119
|
+
renderCurrentForcePattern({
|
|
120
|
+
fromDirectionDeg: 0,
|
|
121
|
+
radius: 112,
|
|
122
|
+
patternScale: 1.39,
|
|
123
|
+
})
|
|
124
|
+
);
|
|
125
|
+
expect(flat).not.toContain('animateTransform');
|
|
126
|
+
expect(flat).toContain('stop-opacity=1');
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
it('falls back to full intensity for a non-finite waveHeight', () => {
|
|
130
|
+
const flat = flatten(
|
|
131
|
+
renderCurrentForcePattern({
|
|
132
|
+
fromDirectionDeg: 0,
|
|
133
|
+
radius: 112,
|
|
134
|
+
patternScale: 1.39,
|
|
135
|
+
waveHeight: Number.NaN,
|
|
136
|
+
})
|
|
137
|
+
);
|
|
138
|
+
expect(flat).toContain('stop-opacity=1');
|
|
139
|
+
expect(flat).not.toContain('NaN');
|
|
140
|
+
});
|
|
99
141
|
});
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {svg, SVGTemplateResult} from 'lit';
|
|
1
|
+
import {nothing, svg, SVGTemplateResult} from 'lit';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Options for the force-graphics pattern underlays (wind streaks / current
|
|
@@ -19,6 +19,22 @@ export interface ForcePatternOptions {
|
|
|
19
19
|
color?: string;
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
+
/** Wave tuning for the current band pattern, on top of the shared options. */
|
|
23
|
+
export interface CurrentForcePatternOptions extends ForcePatternOptions {
|
|
24
|
+
/**
|
|
25
|
+
* Wavelength as a multiplier on the design band spacing (1 = design,
|
|
26
|
+
* 0.5 = twice as dense). Non-finite or non-positive values fall back to 1.
|
|
27
|
+
*/
|
|
28
|
+
waveLength?: number;
|
|
29
|
+
/** Wave intensity: peak opacity the band gradient fades up to (0–1). */
|
|
30
|
+
waveHeight?: number;
|
|
31
|
+
/**
|
|
32
|
+
* Drift speed in wavelengths per second, moving with the flow (negative
|
|
33
|
+
* drifts against it). 0 / undefined keeps the pattern static.
|
|
34
|
+
*/
|
|
35
|
+
waveSpeed?: number;
|
|
36
|
+
}
|
|
37
|
+
|
|
22
38
|
const DESIGN_PATTERN_SQUARE = 256;
|
|
23
39
|
const WIND_TILE = 24;
|
|
24
40
|
/**
|
|
@@ -64,21 +80,39 @@ export function renderWindForcePattern(
|
|
|
64
80
|
/**
|
|
65
81
|
* Current force-graphics: soft-edged gradient bands (48-unit sawtooth,
|
|
66
82
|
* transparent → opaque), perpendicular to the flow, clipped to a circle and
|
|
67
|
-
* rotated by the from-direction.
|
|
83
|
+
* rotated by the from-direction. `waveLength` stretches the band spacing,
|
|
84
|
+
* `waveHeight` scales the gradient's peak opacity, and a non-zero `waveSpeed`
|
|
85
|
+
* drifts the field with the flow (one wavelength per `1/waveSpeed` seconds)
|
|
86
|
+
* via a declarative SMIL loop.
|
|
68
87
|
*/
|
|
69
88
|
export function renderCurrentForcePattern(
|
|
70
|
-
options:
|
|
89
|
+
options: CurrentForcePatternOptions
|
|
71
90
|
): SVGTemplateResult {
|
|
72
91
|
const {fromDirectionDeg, radius, patternScale} = options;
|
|
73
92
|
const color = options.color ?? DEFAULT_COLOR;
|
|
74
|
-
const
|
|
93
|
+
const lengthScale =
|
|
94
|
+
Number.isFinite(options.waveLength) && options.waveLength! > 0
|
|
95
|
+
? options.waveLength!
|
|
96
|
+
: 1;
|
|
97
|
+
const intensity = Number.isFinite(options.waveHeight)
|
|
98
|
+
? Math.max(0, Math.min(1, options.waveHeight!))
|
|
99
|
+
: 1;
|
|
100
|
+
const speed = Number.isFinite(options.waveSpeed) ? options.waveSpeed! : 0;
|
|
101
|
+
const tile = CURRENT_TILE * patternScale * lengthScale;
|
|
75
102
|
const side = DESIGN_PATTERN_SQUARE * patternScale;
|
|
76
|
-
const phase = CURRENT_TILE_PHASE_OFFSET * patternScale;
|
|
103
|
+
const phase = CURRENT_TILE_PHASE_OFFSET * patternScale * lengthScale;
|
|
104
|
+
// The pattern is anchored in the rect's user space, so translating the
|
|
105
|
+
// wrapper group drifts the whole band field; the rect is one tile taller on
|
|
106
|
+
// each end to stay covering the clip disc across the loop.
|
|
107
|
+
const drift =
|
|
108
|
+
speed !== 0
|
|
109
|
+
? svg`<animateTransform attributeName="transform" attributeType="XML" type="translate" from="0 0" to="0 ${tile * Math.sign(speed)}" dur="${1 / Math.abs(speed)}s" repeatCount="indefinite"/>`
|
|
110
|
+
: nothing;
|
|
77
111
|
return svg`
|
|
78
112
|
<defs>
|
|
79
113
|
<linearGradient id="current-force-band-gradient" x1="24" y1="0" x2="24" y2="48" gradientUnits="userSpaceOnUse">
|
|
80
114
|
<stop stop-color=${color} stop-opacity="0"/>
|
|
81
|
-
<stop offset="1" stop-color=${color}/>
|
|
115
|
+
<stop offset="1" stop-color=${color} stop-opacity=${intensity}/>
|
|
82
116
|
</linearGradient>
|
|
83
117
|
<pattern id="current-force-pattern" patternUnits="userSpaceOnUse" x=${-side / 2 + phase} y=${-side / 2 + phase} width=${tile} height=${tile} viewBox="0 0 48 48" preserveAspectRatio="none">
|
|
84
118
|
<rect width="48" height="48" fill="url(#current-force-band-gradient)"/>
|
|
@@ -86,7 +120,10 @@ export function renderCurrentForcePattern(
|
|
|
86
120
|
<clipPath id="current-force-clip"><circle cx="0" cy="0" r=${radius}/></clipPath>
|
|
87
121
|
</defs>
|
|
88
122
|
<g clip-path="url(#current-force-clip)" transform="rotate(${fromDirectionDeg})">
|
|
89
|
-
<
|
|
123
|
+
<g>
|
|
124
|
+
${drift}
|
|
125
|
+
<rect x=${-side / 2} y=${-side / 2 - tile} width=${side} height=${side + 2 * tile} fill="url(#current-force-pattern)"/>
|
|
126
|
+
</g>
|
|
90
127
|
</g>
|
|
91
128
|
`;
|
|
92
129
|
}
|
|
@@ -55,6 +55,7 @@ import {
|
|
|
55
55
|
renderCurrent,
|
|
56
56
|
renderCurrentCentered,
|
|
57
57
|
renderWind,
|
|
58
|
+
WIND_ICON_TIP_TO_BOX_INNER,
|
|
58
59
|
} from './environment.js';
|
|
59
60
|
import {customElement} from '../../decorator.js';
|
|
60
61
|
import {type ZoomToFitArcFrame} from '../../svghelpers/arc-frame.js';
|
|
@@ -130,6 +131,17 @@ export function innerRingRadiusFor(type: WatchCircleType): number {
|
|
|
130
131
|
|
|
131
132
|
const RADIAL_SETPOINT_INWARD_ADJUST = 4;
|
|
132
133
|
|
|
134
|
+
/**
|
|
135
|
+
* Default anchors for the wind/current icons outside the outer ring (the
|
|
136
|
+
* compass layout): the 48-unit icon box sits 4 units off the ring, spanning
|
|
137
|
+
* 188–236 (OpenBridge 6.1 compass, node 19846-157200). The current chevron
|
|
138
|
+
* anchors by its tip at the box inner edge; the wind anchor adds the glyph's
|
|
139
|
+
* inward overhang so its box starts at the same edge.
|
|
140
|
+
*/
|
|
141
|
+
const CURRENT_ICON_OUTSIDE_RADIUS = OUTER_RING_RADIUS + 4;
|
|
142
|
+
const WIND_ICON_OUTSIDE_RADIUS =
|
|
143
|
+
CURRENT_ICON_OUTSIDE_RADIUS + WIND_ICON_TIP_TO_BOX_INNER;
|
|
144
|
+
|
|
133
145
|
/**
|
|
134
146
|
* `<obc-watch>` - Core SVG renderer for circular/radial watch-based instruments.
|
|
135
147
|
*
|
|
@@ -966,10 +978,13 @@ export class ObcWatch extends LitElement {
|
|
|
966
978
|
: nothing;
|
|
967
979
|
|
|
968
980
|
// Compute label positions once – used for both rendering and crosshair
|
|
969
|
-
// knockout. NSWE labels
|
|
970
|
-
//
|
|
981
|
+
// knockout. NSWE labels are px-fixed outside decor, so they follow the
|
|
982
|
+
// same labelsHidden degradation as tick label texts. The north arrow is
|
|
983
|
+
// exempt: below the small-scale threshold it renders as a compact
|
|
984
|
+
// triangle at the ring that scales with the face, so it stays visible
|
|
985
|
+
// on the smallest faces without clipping.
|
|
971
986
|
const showNsweLabels = this.showLabels && !this._labelsHidden;
|
|
972
|
-
const showNorthArrow = this.northArrow
|
|
987
|
+
const showNorthArrow = this.northArrow;
|
|
973
988
|
const insideLabels = this.tickmarksInside && showNsweLabels;
|
|
974
989
|
const includeNorth = !this.northArrow;
|
|
975
990
|
const labelPositions = showNsweLabels
|
|
@@ -1006,7 +1021,7 @@ export class ObcWatch extends LitElement {
|
|
|
1006
1021
|
? svg`<g transform="scale(${this.scaleWindIcon})">${renderWind({
|
|
1007
1022
|
windKnots: this.windKnots,
|
|
1008
1023
|
fromDirectionDeg: this.windFromDirectionDeg,
|
|
1009
|
-
radius: this.windSymbolRadius ??
|
|
1024
|
+
radius: this.windSymbolRadius ?? WIND_ICON_OUTSIDE_RADIUS,
|
|
1010
1025
|
color: this.windColor,
|
|
1011
1026
|
})}</g>`
|
|
1012
1027
|
: nothing;
|
|
@@ -1022,7 +1037,7 @@ export class ObcWatch extends LitElement {
|
|
|
1022
1037
|
: renderCurrent({
|
|
1023
1038
|
current: this.current,
|
|
1024
1039
|
fromDirectionDeg: this.currentFromDirectionDeg,
|
|
1025
|
-
radius: this.currentSymbolRadius ??
|
|
1040
|
+
radius: this.currentSymbolRadius ?? CURRENT_ICON_OUTSIDE_RADIUS,
|
|
1026
1041
|
color: this.currentColor,
|
|
1027
1042
|
})
|
|
1028
1043
|
: nothing;
|
|
@@ -3,8 +3,10 @@ import {resolveWindArrowPlacement, WindVariant} from './wind.js';
|
|
|
3
3
|
|
|
4
4
|
describe('resolveWindArrowPlacement', () => {
|
|
5
5
|
it('matches the OpenBridge 6.1 design values (effective tip = radius × scale)', () => {
|
|
6
|
+
// Large: 48-unit icon box fills the double-face track band (112–160);
|
|
7
|
+
// tip anchor = 112 + inward overhang 3.1094 of the 2× glyph.
|
|
6
8
|
expect(resolveWindArrowPlacement(WindVariant.large)).toEqual({
|
|
7
|
-
windSymbolRadius:
|
|
9
|
+
windSymbolRadius: 112 + (24 - 22.4453) * 2,
|
|
8
10
|
scaleWindIcon: 1.0,
|
|
9
11
|
});
|
|
10
12
|
expect(resolveWindArrowPlacement(WindVariant.medium)).toEqual({
|
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
WatchCircleType,
|
|
8
8
|
innerRingRadiusFor,
|
|
9
9
|
} from '../watch/watch.js';
|
|
10
|
+
import {WIND_ICON_TIP_TO_BOX_INNER} from '../watch/environment.js';
|
|
10
11
|
import {renderWindForcePattern} from '../watch/force-pattern.js';
|
|
11
12
|
import {Priority} from '../types.js';
|
|
12
13
|
import {customElement} from '../../decorator.js';
|
|
@@ -320,8 +321,11 @@ function resolveHistogramMaxRadius(variant: ResolvedWindVariant): number {
|
|
|
320
321
|
* `scaleWindIcon` scales the arrow glyph — and, because the scale group wraps
|
|
321
322
|
* the translated glyph, the effective tip radius is `radius × scale`.
|
|
322
323
|
*
|
|
323
|
-
*
|
|
324
|
-
*
|
|
324
|
+
* Large places the 48-unit icon box exactly inside the double-face track
|
|
325
|
+
* band (112–160), per the OpenBridge 6.1 design (the icon box spans the
|
|
326
|
+
* band, node 19663-140867); the tip anchor is the box inner edge plus the
|
|
327
|
+
* glyph's inward overhang. Medium ≈93 and small ≈8 (touching center) are
|
|
328
|
+
* measured from the Figma variants (node 6552-102891).
|
|
325
329
|
*/
|
|
326
330
|
export function resolveWindArrowPlacement(variant: ResolvedWindVariant): {
|
|
327
331
|
windSymbolRadius: number;
|
|
@@ -329,7 +333,12 @@ export function resolveWindArrowPlacement(variant: ResolvedWindVariant): {
|
|
|
329
333
|
} {
|
|
330
334
|
switch (variant) {
|
|
331
335
|
case WindVariant.large:
|
|
332
|
-
return {
|
|
336
|
+
return {
|
|
337
|
+
windSymbolRadius:
|
|
338
|
+
innerRingRadiusFor(WatchCircleType.double) +
|
|
339
|
+
WIND_ICON_TIP_TO_BOX_INNER,
|
|
340
|
+
scaleWindIcon: 1.0,
|
|
341
|
+
};
|
|
333
342
|
case WindVariant.medium:
|
|
334
343
|
return {windSymbolRadius: 62, scaleWindIcon: 1.5};
|
|
335
344
|
case WindVariant.small:
|