@oicl/openbridge-webcomponents-full-bundle 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
- package/script/check-slot-event-docs.ts +35 -0
- package/src/bars-graphs/donut-chart/donut-chart.ts +18 -16
- package/src/bars-graphs/pie-chart/pie-chart.ts +14 -12
- package/src/bars-graphs/polar-chart/polar-chart.ts +19 -16
- package/src/bars-graphs/radial-bar-chart/radial-bar-chart.ts +8 -8
- package/src/building-blocks/chart-line/chart-line-base.ts +8 -25
- package/src/building-blocks/instrument-radial/instrument-radial.stories.ts +187 -6
- package/src/building-blocks/instrument-radial/instrument-radial.ts +98 -47
- package/src/integration-systems/integration-bar/integration-bar.ts +20 -24
- package/src/integration-systems/integration-button/integration-button.ts +15 -13
- package/src/navigation-instruments/azimuth-thruster/azimuth-thruster.stories.ts +78 -1
- package/src/navigation-instruments/azimuth-thruster/azimuth-thruster.ts +55 -11
- package/src/navigation-instruments/compass/compass.stories.ts +88 -1
- package/src/navigation-instruments/compass/compass.ts +99 -46
- package/src/navigation-instruments/compass-flat/compass-flat.ts +8 -9
- package/src/navigation-instruments/compass-sector/compass-sector.ts +7 -0
- package/src/navigation-instruments/gauge-radial/gauge-radial.css +32 -2
- package/src/navigation-instruments/gauge-radial/gauge-radial.stories.ts +265 -1
- package/src/navigation-instruments/gauge-radial/gauge-radial.ts +59 -1
- package/src/navigation-instruments/gauge-trend/gauge-trend.ts +0 -5
- package/src/navigation-instruments/graph-mini/graph-mini.ts +1 -1
- package/src/navigation-instruments/heading/heading.stories.ts +92 -1
- package/src/navigation-instruments/heading/heading.ts +50 -16
- package/src/navigation-instruments/indicator-graph/indicator-graph.ts +1 -1
- package/src/navigation-instruments/rudder/rudder.stories.ts +83 -1
- package/src/navigation-instruments/rudder/rudder.ts +61 -34
- package/src/navigation-instruments/speed-gauge/speed-gauge.stories.ts +94 -1
- package/src/navigation-instruments/speed-gauge/speed-gauge.ts +57 -4
- package/src/navigation-instruments/watch/watch.stories.ts +140 -1
- package/src/navigation-instruments/watch/watch.ts +100 -60
- package/src/storybook-util.ts +59 -0
- package/src/svghelpers/radial-frame.spec.ts +307 -0
- package/src/svghelpers/radial-frame.ts +508 -0
|
@@ -5,6 +5,14 @@ import {Tickmark, TickmarkType} from '../watch/tickmark.js';
|
|
|
5
5
|
import {arrow, ArrowStyle} from './arrow.js';
|
|
6
6
|
import {AdviceState, AngleAdvice, AngleAdviceRaw} from '../watch/advice.js';
|
|
7
7
|
import {ResizeController} from '@lit-labs/observers/resize-controller.js';
|
|
8
|
+
import {
|
|
9
|
+
applyPinnedHostSize,
|
|
10
|
+
computeRadialFrame,
|
|
11
|
+
measureContainerPx,
|
|
12
|
+
NORTH_ARROW_WIDTH_PX,
|
|
13
|
+
NSWE_LABEL_WIDTH_PX,
|
|
14
|
+
type RadialFrame,
|
|
15
|
+
} from '../../svghelpers/radial-frame.js';
|
|
8
16
|
import {WatchCircleType} from '../watch/watch.js';
|
|
9
17
|
import {SetpointBundle} from '../../svghelpers/setpoint-bundle.js';
|
|
10
18
|
import {Priority} from '../types.js';
|
|
@@ -58,6 +66,15 @@ export class ObcHeading extends LitElement {
|
|
|
58
66
|
@property({type: Boolean}) showLabels: boolean = false;
|
|
59
67
|
/** When true, labels and north arrow are placed inside the outer ring. */
|
|
60
68
|
@property({type: Boolean}) tickmarksInside: boolean = false;
|
|
69
|
+
/**
|
|
70
|
+
* Outer-ring diameter in CSS pixels. When set, the instrument renders at a
|
|
71
|
+
* fixed intrinsic size derived from the ring, arc shape and label reserve —
|
|
72
|
+
* so instruments sharing the same value have identical ring circumference
|
|
73
|
+
* regardless of label width or arc extent (like obc-donut-chart's
|
|
74
|
+
* fixedHeight). When unset (default), the instrument fills its container.
|
|
75
|
+
*/
|
|
76
|
+
@property({type: Number, attribute: 'face-diameter'})
|
|
77
|
+
faceDiameter: number | undefined;
|
|
61
78
|
|
|
62
79
|
private _headingSp = new SetpointBundle({
|
|
63
80
|
angularWraparound: true,
|
|
@@ -88,18 +105,30 @@ export class ObcHeading extends LitElement {
|
|
|
88
105
|
// function is called on resize of the element
|
|
89
106
|
private _resizeController = new ResizeController(this, {});
|
|
90
107
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
108
|
+
/**
|
|
109
|
+
* Pixel cost of the outside decor: the always-rendered north-arrow glyph
|
|
110
|
+
* plus, only while shown, the NSWE labels (both keep a constant on-screen
|
|
111
|
+
* size via `1/scale` terms). Feeds the frame's width-aware reserve,
|
|
112
|
+
* replacing the former empirical `72 + delta(clientSize)` padding.
|
|
113
|
+
*/
|
|
114
|
+
private getOutsideDecorPx(): number {
|
|
115
|
+
if (this.tickmarksInside) {
|
|
116
|
+
return 0;
|
|
100
117
|
}
|
|
118
|
+
return NORTH_ARROW_WIDTH_PX + (this.showLabels ? NSWE_LABEL_WIDTH_PX : 0);
|
|
119
|
+
}
|
|
101
120
|
|
|
102
|
-
|
|
121
|
+
/** Whether the host size styles were set by applyPinnedHostSize. */
|
|
122
|
+
private _hostSizePinned = false;
|
|
123
|
+
private _frame: RadialFrame | undefined;
|
|
124
|
+
|
|
125
|
+
override updated(changed: PropertyValues): void {
|
|
126
|
+
super.updated(changed);
|
|
127
|
+
this._hostSizePinned = applyPinnedHostSize(
|
|
128
|
+
this,
|
|
129
|
+
this._frame,
|
|
130
|
+
this._hostSizePinned
|
|
131
|
+
);
|
|
103
132
|
}
|
|
104
133
|
|
|
105
134
|
private get angleAdviceRaw(): AngleAdviceRaw[] {
|
|
@@ -140,22 +169,27 @@ export class ObcHeading extends LitElement {
|
|
|
140
169
|
{angle: 270, type: TickmarkType.main},
|
|
141
170
|
];
|
|
142
171
|
|
|
143
|
-
const
|
|
144
|
-
|
|
145
|
-
|
|
172
|
+
const frame = computeRadialFrame({
|
|
173
|
+
basePadding: 72,
|
|
174
|
+
labelWidthPx: this.getOutsideDecorPx(),
|
|
175
|
+
containerPx: measureContainerPx(this),
|
|
176
|
+
faceDiameter: this.faceDiameter,
|
|
177
|
+
});
|
|
178
|
+
this._frame = frame;
|
|
179
|
+
const viewBox = frame.viewBox;
|
|
146
180
|
|
|
147
181
|
return html`
|
|
148
182
|
<div class="container">
|
|
149
183
|
<obc-watch
|
|
150
184
|
.touching=${this.touching}
|
|
151
|
-
.
|
|
185
|
+
.arcFrame=${frame}
|
|
152
186
|
.advices=${this.angleAdviceRaw}
|
|
153
187
|
.tickmarks=${tickmarks}
|
|
154
188
|
.watchCircleType=${WatchCircleType.single}
|
|
155
|
-
.showLabels=${this.showLabels}
|
|
189
|
+
.showLabels=${this.showLabels && !frame.labelsHidden}
|
|
156
190
|
.tickmarksInside=${this.tickmarksInside}
|
|
157
191
|
.crosshairEnabled=${true}
|
|
158
|
-
.northArrow=${
|
|
192
|
+
.northArrow=${!frame.labelsHidden}
|
|
159
193
|
.angleSetpoint=${this.headingSetpoint ?? undefined}
|
|
160
194
|
.newAngleSetpoint=${this.newHeadingSetpoint}
|
|
161
195
|
.atAngleSetpoint=${this._headingSp.computeAtSetpoint(this.heading)}
|
|
@@ -26,11 +26,11 @@ export interface ObcIndicatorGraphLayout {
|
|
|
26
26
|
* @element obc-indicator-graph
|
|
27
27
|
* @description A mini graph component
|
|
28
28
|
*
|
|
29
|
-
* @property {Array} data - The data to display in the graph, first array is the x values, second array is the y values
|
|
30
29
|
* @beta
|
|
31
30
|
*/
|
|
32
31
|
@customElement('obc-indicator-graph')
|
|
33
32
|
export class ObcIndicatorGraph extends LitElement {
|
|
33
|
+
/** The data to display in the graph, first array is the x values, second array is the y values */
|
|
34
34
|
@property({type: Array})
|
|
35
35
|
data: [number[], number[]] = [[], []];
|
|
36
36
|
|
|
@@ -1,7 +1,13 @@
|
|
|
1
1
|
import type {Meta, StoryObj} from '@storybook/web-components-vite';
|
|
2
2
|
import {ObcRudder, ObcRudderVariant} from './rudder.js';
|
|
3
3
|
import './rudder.js';
|
|
4
|
-
import {
|
|
4
|
+
import {html} from 'lit';
|
|
5
|
+
import {
|
|
6
|
+
playgroundColumn,
|
|
7
|
+
resizableStoryBox,
|
|
8
|
+
storyHint,
|
|
9
|
+
widthDecorator,
|
|
10
|
+
} from '../../storybook-util.js';
|
|
5
11
|
import {TickmarkStyle} from '../watch/tickmark.js';
|
|
6
12
|
import {InstrumentState, Priority} from '../types.js';
|
|
7
13
|
const meta: Meta<typeof ObcRudder> = {
|
|
@@ -20,6 +26,11 @@ const meta: Meta<typeof ObcRudder> = {
|
|
|
20
26
|
},
|
|
21
27
|
argTypes: {
|
|
22
28
|
width: {control: {type: 'range', min: 32, max: 1028, step: 1}},
|
|
29
|
+
faceDiameter: {
|
|
30
|
+
control: {type: 'range', min: 100, max: 600, step: 10},
|
|
31
|
+
description:
|
|
32
|
+
'Pins the outer-ring diameter in px (fixed intrinsic size, equal circumference across instruments). Clear to return to fill-the-container sizing.',
|
|
33
|
+
},
|
|
23
34
|
angle: {control: {type: 'range', min: -90, max: 90, step: 1}},
|
|
24
35
|
maxAngle: {control: {type: 'range', min: 2, max: 90, step: 1}},
|
|
25
36
|
setpoint: {control: {type: 'range', min: -90, max: 90, step: 1}},
|
|
@@ -72,3 +83,74 @@ export const ZoomedInNarrow: Story = {
|
|
|
72
83
|
showLabels: true,
|
|
73
84
|
},
|
|
74
85
|
};
|
|
86
|
+
|
|
87
|
+
type SizingPlaygroundArgs = Partial<ObcRudder> & {
|
|
88
|
+
lockFaceDiameter?: boolean;
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Interactive sizing playground: drag the dashed box's bottom-right corner to
|
|
93
|
+
* resize it. The first rudder is pinned to a fixed intrinsic size by the
|
|
94
|
+
* `faceDiameter` control (its box is wider than tall, matching the 40% top
|
|
95
|
+
* clip), the second adapts to the remaining flex space, and the third is a
|
|
96
|
+
* zoomed narrow arc (`zoomToFitArc`) showing that the reserve composes with
|
|
97
|
+
* zoom (issue #1021). Enable `lockFaceDiameter` to pin all three to the same
|
|
98
|
+
* circumference. Related: *Sizing Playground* stories under Building
|
|
99
|
+
* Blocks/Watch, Building Blocks/Instrument Radial and Instruments/Gauge
|
|
100
|
+
* Radial.
|
|
101
|
+
*/
|
|
102
|
+
export const SizingPlayground: StoryObj<SizingPlaygroundArgs> = {
|
|
103
|
+
name: 'Sizing Playground — FaceDiameter + Resizable (Manual)',
|
|
104
|
+
tags: ['skip-test'],
|
|
105
|
+
parameters: {widthDecorator: false},
|
|
106
|
+
args: {
|
|
107
|
+
faceDiameter: 260,
|
|
108
|
+
lockFaceDiameter: false,
|
|
109
|
+
},
|
|
110
|
+
argTypes: {
|
|
111
|
+
lockFaceDiameter: {
|
|
112
|
+
control: 'boolean',
|
|
113
|
+
description:
|
|
114
|
+
'Apply faceDiameter to every instance (equal circumference) instead of only the first.',
|
|
115
|
+
},
|
|
116
|
+
},
|
|
117
|
+
render: (args) => {
|
|
118
|
+
const instances = [
|
|
119
|
+
{label: 'half circle', maxAngle: 45, zoom: false},
|
|
120
|
+
{label: 'half circle', maxAngle: 45, zoom: false},
|
|
121
|
+
{label: 'zoomed ±20°', maxAngle: 20, zoom: true},
|
|
122
|
+
];
|
|
123
|
+
const fd = (index: number) =>
|
|
124
|
+
index === 0 || args.lockFaceDiameter ? args.faceDiameter : undefined;
|
|
125
|
+
const caption = (index: number, label: string) =>
|
|
126
|
+
fd(index) !== undefined
|
|
127
|
+
? `${label} — pinned ${fd(index)}px`
|
|
128
|
+
: `${label} — adaptive (flex)`;
|
|
129
|
+
return html`
|
|
130
|
+
${storyHint(
|
|
131
|
+
'Drag the bottom-right corner of the dashed box to resize it. The first rudder is pinned by the faceDiameter control; the second and the zoomed narrow arc adapt to the remaining flex space. Enable lockFaceDiameter to pin all three to the same circumference.'
|
|
132
|
+
)}
|
|
133
|
+
${resizableStoryBox(
|
|
134
|
+
html`
|
|
135
|
+
${instances.map((g, index) =>
|
|
136
|
+
playgroundColumn(
|
|
137
|
+
caption(index, g.label),
|
|
138
|
+
html`
|
|
139
|
+
<obc-rudder
|
|
140
|
+
.angle=${15}
|
|
141
|
+
.setpoint=${30}
|
|
142
|
+
.maxAngle=${g.maxAngle}
|
|
143
|
+
.zoomToFitArc=${g.zoom}
|
|
144
|
+
.showLabels=${true}
|
|
145
|
+
.faceDiameter=${fd(index)}
|
|
146
|
+
></obc-rudder>
|
|
147
|
+
`,
|
|
148
|
+
{pinned: fd(index) !== undefined}
|
|
149
|
+
)
|
|
150
|
+
)}
|
|
151
|
+
`,
|
|
152
|
+
{width: 760, height: 280}
|
|
153
|
+
)}
|
|
154
|
+
`;
|
|
155
|
+
},
|
|
156
|
+
};
|
|
@@ -1,20 +1,21 @@
|
|
|
1
|
-
import {LitElement, css, html, nothing, svg} from 'lit';
|
|
1
|
+
import {LitElement, PropertyValues, css, html, nothing, svg} from 'lit';
|
|
2
2
|
import {property} from 'lit/decorators.js';
|
|
3
|
+
import {ResizeController} from '@lit-labs/observers/resize-controller.js';
|
|
3
4
|
import '../watch/watch.js';
|
|
4
5
|
import {Tickmark, TickmarkStyle, TickmarkType} from '../watch/tickmark.js';
|
|
5
|
-
import {
|
|
6
|
-
OUTER_RING_RADIUS,
|
|
7
|
-
WatchCircleType,
|
|
8
|
-
innerRingRadiusFor,
|
|
9
|
-
} from '../watch/watch.js';
|
|
6
|
+
import {WatchCircleType, innerRingRadiusFor} from '../watch/watch.js';
|
|
10
7
|
import {InstrumentState, Priority} from '../types.js';
|
|
11
8
|
import {SetpointMixin} from '../../svghelpers/setpoint-mixin.js';
|
|
12
9
|
import {AdviceState, AngleAdvice, AngleAdviceRaw} from '../watch/advice.js';
|
|
13
10
|
import {customElement} from '../../decorator.js';
|
|
14
11
|
import {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
12
|
+
applyPinnedHostSize,
|
|
13
|
+
computeRadialFrame,
|
|
14
|
+
estimateLabelWidthPx,
|
|
15
|
+
measureContainerPx,
|
|
16
|
+
observeInnerBox,
|
|
17
|
+
type RadialFrame,
|
|
18
|
+
} from '../../svghelpers/radial-frame.js';
|
|
18
19
|
|
|
19
20
|
export enum ObcRudderVariant {
|
|
20
21
|
Bar = 'bar',
|
|
@@ -95,9 +96,37 @@ export class ObcRudder extends SetpointMixin(LitElement) {
|
|
|
95
96
|
TickmarkStyle.regular;
|
|
96
97
|
@property({type: Array, attribute: false}) advices: AngleAdvice[] = [];
|
|
97
98
|
@property({type: Boolean}) zoomToFitArc: boolean = false;
|
|
99
|
+
/**
|
|
100
|
+
* Outer-ring diameter in CSS pixels. When set, the instrument renders at a
|
|
101
|
+
* fixed intrinsic size derived from the ring, arc shape and label reserve —
|
|
102
|
+
* so instruments sharing the same value have identical ring circumference
|
|
103
|
+
* regardless of label width or arc extent (like obc-donut-chart's
|
|
104
|
+
* fixedHeight). When unset (default), the instrument fills its container.
|
|
105
|
+
*/
|
|
106
|
+
@property({type: Number, attribute: 'face-diameter'})
|
|
107
|
+
faceDiameter: number | undefined;
|
|
98
108
|
|
|
99
109
|
private _radiusOffset = 0;
|
|
100
|
-
private
|
|
110
|
+
private _frame: RadialFrame | undefined;
|
|
111
|
+
|
|
112
|
+
/** Whether the host size styles were set by applyPinnedHostSize. */
|
|
113
|
+
private _hostSizePinned = false;
|
|
114
|
+
|
|
115
|
+
private _resizeController = new ResizeController(this, {});
|
|
116
|
+
|
|
117
|
+
override firstUpdated(changed: PropertyValues): void {
|
|
118
|
+
super.firstUpdated(changed);
|
|
119
|
+
observeInnerBox(this._resizeController, this.renderRoot);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
override updated(changed: PropertyValues): void {
|
|
123
|
+
super.updated(changed);
|
|
124
|
+
this._hostSizePinned = applyPinnedHostSize(
|
|
125
|
+
this,
|
|
126
|
+
this._frame,
|
|
127
|
+
this._hostSizePinned
|
|
128
|
+
);
|
|
129
|
+
}
|
|
101
130
|
|
|
102
131
|
private get _needleTransform(): string {
|
|
103
132
|
const rOff = this._radiusOffset;
|
|
@@ -243,33 +272,32 @@ export class ObcRudder extends SetpointMixin(LitElement) {
|
|
|
243
272
|
};
|
|
244
273
|
});
|
|
245
274
|
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
275
|
+
const frame = computeRadialFrame({
|
|
276
|
+
basePadding: 48,
|
|
277
|
+
labelWidthPx: this.tickmarksInside
|
|
278
|
+
? 0
|
|
279
|
+
: estimateLabelWidthPx(tickmarks.map((t) => t.text)),
|
|
280
|
+
clips: this.zoomToFitArc
|
|
281
|
+
? undefined
|
|
282
|
+
: {top: 40, bottom: 0, left: 0, right: 0},
|
|
283
|
+
containerPx: measureContainerPx(this),
|
|
284
|
+
faceDiameter: this.faceDiameter,
|
|
285
|
+
zoomToFitArc: this.zoomToFitArc,
|
|
286
|
+
areas,
|
|
287
|
+
innerRadius: innerRingRadiusFor(WatchCircleType.double),
|
|
288
|
+
});
|
|
289
|
+
this._radiusOffset = frame.radiusOffset;
|
|
290
|
+
this._frame = frame;
|
|
291
|
+
const shownTickmarks = frame.labelsHidden
|
|
292
|
+
? tickmarks.map((t) => ({...t, text: undefined}))
|
|
293
|
+
: tickmarks;
|
|
294
|
+
const overlayViewBox = frame.viewBox;
|
|
265
295
|
|
|
266
296
|
return html`
|
|
267
297
|
<div class="container">
|
|
268
298
|
<obc-watch
|
|
269
299
|
.touching=${this.touching}
|
|
270
|
-
.
|
|
271
|
-
.zoomToFitArc=${this.zoomToFitArc}
|
|
272
|
-
.arcFrame=${this._arcFrame}
|
|
300
|
+
.arcFrame=${frame}
|
|
273
301
|
.areas=${areas}
|
|
274
302
|
.angleSetpoint=${setpointAngle}
|
|
275
303
|
.newAngleSetpoint=${this.newSetpoint !== undefined
|
|
@@ -279,8 +307,7 @@ export class ObcRudder extends SetpointMixin(LitElement) {
|
|
|
279
307
|
.angleSetpointAtZeroDeadband=${this.setpointAtZeroDeadband}
|
|
280
308
|
.setpointOverride=${this.setpointOverride}
|
|
281
309
|
.animateSetpoint=${this.animateSetpoint}
|
|
282
|
-
.
|
|
283
|
-
.tickmarks=${tickmarks}
|
|
310
|
+
.tickmarks=${shownTickmarks}
|
|
284
311
|
.tickmarksInside=${this.tickmarksInside}
|
|
285
312
|
.tickmarkStyle=${this.tickmarkStyle}
|
|
286
313
|
.watchCircleType=${WatchCircleType.double}
|
|
@@ -1,7 +1,13 @@
|
|
|
1
1
|
import type {Meta, StoryObj} from '@storybook/web-components-vite';
|
|
2
2
|
import {ObcSpeedGauge, ObcSpeedGaugeNeedleType} from './speed-gauge.js';
|
|
3
3
|
import './speed-gauge.js';
|
|
4
|
-
import {
|
|
4
|
+
import {html} from 'lit';
|
|
5
|
+
import {
|
|
6
|
+
playgroundColumn,
|
|
7
|
+
resizableStoryBox,
|
|
8
|
+
storyHint,
|
|
9
|
+
widthDecorator,
|
|
10
|
+
} from '../../storybook-util.js';
|
|
5
11
|
import {AdviceType} from '../watch/advice.js';
|
|
6
12
|
import {TickmarkStyle} from '../watch/tickmark.js';
|
|
7
13
|
import {Priority} from '../types.js';
|
|
@@ -33,6 +39,11 @@ const meta: Meta<typeof ObcSpeedGauge> = {
|
|
|
33
39
|
options: Object.values(TickmarkStyle),
|
|
34
40
|
},
|
|
35
41
|
hasReadout: {control: 'boolean'},
|
|
42
|
+
faceDiameter: {
|
|
43
|
+
control: {type: 'range', min: 100, max: 600, step: 10},
|
|
44
|
+
description:
|
|
45
|
+
'Pins the outer-ring diameter in px (fixed intrinsic size, equal circumference across instruments). Clear to return to fill-the-container sizing.',
|
|
46
|
+
},
|
|
36
47
|
label: {control: 'text'},
|
|
37
48
|
unit: {control: 'text'},
|
|
38
49
|
fractionDigits: {control: 'number'},
|
|
@@ -73,3 +84,85 @@ export const Readout: Story = {
|
|
|
73
84
|
hasReadout: true,
|
|
74
85
|
},
|
|
75
86
|
};
|
|
87
|
+
|
|
88
|
+
export const LabelRoomHighSpeed: Story = {
|
|
89
|
+
name: 'Label Room — 4-Digit Scale in A Short Cell (#1021)',
|
|
90
|
+
args: {
|
|
91
|
+
minSpeed: 0,
|
|
92
|
+
maxSpeed: 3600,
|
|
93
|
+
speed: 2400,
|
|
94
|
+
tickmarkInterval: 900,
|
|
95
|
+
showLabels: true,
|
|
96
|
+
hasReadout: true,
|
|
97
|
+
width: 600,
|
|
98
|
+
height: 220,
|
|
99
|
+
} as never,
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
type SizingPlaygroundArgs = Partial<ObcSpeedGauge> & {
|
|
103
|
+
lockFaceDiameter?: boolean;
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Interactive sizing playground: drag the dashed box's bottom-right corner to
|
|
108
|
+
* resize it. The first gauge is pinned to a fixed intrinsic size by the
|
|
109
|
+
* `faceDiameter` control, while the second adapts to the remaining flex
|
|
110
|
+
* space, reserving room for its 4-digit labels adaptively (issue #1021).
|
|
111
|
+
* Enable `lockFaceDiameter` to pin both to the same circumference regardless
|
|
112
|
+
* of their label widths. Related: *Sizing Playground* stories under Building
|
|
113
|
+
* Blocks/Watch, Building Blocks/Instrument Radial and Instruments/Gauge
|
|
114
|
+
* Radial.
|
|
115
|
+
*/
|
|
116
|
+
export const SizingPlayground: StoryObj<SizingPlaygroundArgs> = {
|
|
117
|
+
name: 'Sizing Playground — FaceDiameter + Resizable (Manual)',
|
|
118
|
+
tags: ['skip-test'],
|
|
119
|
+
parameters: {widthDecorator: false},
|
|
120
|
+
args: {
|
|
121
|
+
faceDiameter: 220,
|
|
122
|
+
lockFaceDiameter: false,
|
|
123
|
+
},
|
|
124
|
+
argTypes: {
|
|
125
|
+
lockFaceDiameter: {
|
|
126
|
+
control: 'boolean',
|
|
127
|
+
description:
|
|
128
|
+
'Apply faceDiameter to every instance (equal circumference) instead of only the first.',
|
|
129
|
+
},
|
|
130
|
+
},
|
|
131
|
+
render: (args) => {
|
|
132
|
+
const instances = [
|
|
133
|
+
{label: '2-digit scale', max: 40, interval: 10},
|
|
134
|
+
{label: '4-digit scale', max: 3600, interval: 900},
|
|
135
|
+
];
|
|
136
|
+
const fd = (index: number) =>
|
|
137
|
+
index === 0 || args.lockFaceDiameter ? args.faceDiameter : undefined;
|
|
138
|
+
const caption = (index: number, label: string) =>
|
|
139
|
+
fd(index) !== undefined
|
|
140
|
+
? `${label} — pinned ${fd(index)}px`
|
|
141
|
+
: `${label} — adaptive (flex)`;
|
|
142
|
+
return html`
|
|
143
|
+
${storyHint(
|
|
144
|
+
'Drag the bottom-right corner of the dashed box to resize it. The first gauge is pinned by the faceDiameter control; the second adapts to the remaining flex space. Enable lockFaceDiameter to pin both to the same circumference.'
|
|
145
|
+
)}
|
|
146
|
+
${resizableStoryBox(
|
|
147
|
+
html`
|
|
148
|
+
${instances.map((g, index) =>
|
|
149
|
+
playgroundColumn(
|
|
150
|
+
caption(index, g.label),
|
|
151
|
+
html`
|
|
152
|
+
<obc-speed-gauge
|
|
153
|
+
.speed=${g.max * 0.6}
|
|
154
|
+
.maxSpeed=${g.max}
|
|
155
|
+
.tickmarkInterval=${g.interval}
|
|
156
|
+
.showLabels=${true}
|
|
157
|
+
.faceDiameter=${fd(index)}
|
|
158
|
+
></obc-speed-gauge>
|
|
159
|
+
`,
|
|
160
|
+
{pinned: fd(index) !== undefined}
|
|
161
|
+
)
|
|
162
|
+
)}
|
|
163
|
+
`,
|
|
164
|
+
{width: 680, height: 340}
|
|
165
|
+
)}
|
|
166
|
+
`;
|
|
167
|
+
},
|
|
168
|
+
};
|
|
@@ -1,5 +1,14 @@
|
|
|
1
|
-
import {LitElement, css, html, nothing, svg} from 'lit';
|
|
1
|
+
import {LitElement, PropertyValues, css, html, nothing, svg} from 'lit';
|
|
2
2
|
import {property} from 'lit/decorators.js';
|
|
3
|
+
import {ResizeController} from '@lit-labs/observers/resize-controller.js';
|
|
4
|
+
import {
|
|
5
|
+
applyPinnedHostSize,
|
|
6
|
+
computeRadialFrame,
|
|
7
|
+
estimateLabelWidthPx,
|
|
8
|
+
measureContainerPx,
|
|
9
|
+
observeInnerBox,
|
|
10
|
+
type RadialFrame,
|
|
11
|
+
} from '../../svghelpers/radial-frame.js';
|
|
3
12
|
import {Tickmark, TickmarkStyle, TickmarkType} from '../watch/tickmark.js';
|
|
4
13
|
import {WatchCircleType} from '../watch/watch.js';
|
|
5
14
|
import {AdviceType, AngleAdviceRaw, AdviceState} from '../watch/advice.js';
|
|
@@ -113,6 +122,36 @@ export class ObcSpeedGauge extends SetpointMixin(LitElement) {
|
|
|
113
122
|
@property({type: String}) unit = 'KN';
|
|
114
123
|
/** Number of fraction digits shown in the readout. Default `1`. */
|
|
115
124
|
@property({type: Number}) fractionDigits = 1;
|
|
125
|
+
/**
|
|
126
|
+
* Outer-ring diameter in CSS pixels. When set, the instrument renders at a
|
|
127
|
+
* fixed intrinsic size derived from the ring, arc shape and label reserve —
|
|
128
|
+
* so instruments sharing the same value have identical ring circumference
|
|
129
|
+
* regardless of label width or arc extent (like obc-donut-chart's
|
|
130
|
+
* fixedHeight). When unset (default), the instrument fills its container.
|
|
131
|
+
*/
|
|
132
|
+
@property({type: Number, attribute: 'face-diameter'})
|
|
133
|
+
faceDiameter: number | undefined;
|
|
134
|
+
|
|
135
|
+
private _frame: RadialFrame | undefined;
|
|
136
|
+
|
|
137
|
+
/** Whether the host size styles were set by applyPinnedHostSize. */
|
|
138
|
+
private _hostSizePinned = false;
|
|
139
|
+
|
|
140
|
+
private _resizeController = new ResizeController(this, {});
|
|
141
|
+
|
|
142
|
+
override firstUpdated(changed: PropertyValues): void {
|
|
143
|
+
super.firstUpdated(changed);
|
|
144
|
+
observeInnerBox(this._resizeController, this.renderRoot);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
override updated(changed: PropertyValues): void {
|
|
148
|
+
super.updated(changed);
|
|
149
|
+
this._hostSizePinned = applyPinnedHostSize(
|
|
150
|
+
this,
|
|
151
|
+
this._frame,
|
|
152
|
+
this._hostSizePinned
|
|
153
|
+
);
|
|
154
|
+
}
|
|
116
155
|
|
|
117
156
|
getAngle(v: number): number {
|
|
118
157
|
return (v / this.maxSpeed) * (180 + 45) - 90;
|
|
@@ -134,6 +173,20 @@ export class ObcSpeedGauge extends SetpointMixin(LitElement) {
|
|
|
134
173
|
|
|
135
174
|
const maxDigits = 1;
|
|
136
175
|
|
|
176
|
+
const tickmarks = this.tickmarks;
|
|
177
|
+
const frame = computeRadialFrame({
|
|
178
|
+
basePadding: 48,
|
|
179
|
+
labelWidthPx: this.tickmarksInside
|
|
180
|
+
? 0
|
|
181
|
+
: estimateLabelWidthPx(tickmarks.map((t) => t.text)),
|
|
182
|
+
containerPx: measureContainerPx(this),
|
|
183
|
+
faceDiameter: this.faceDiameter,
|
|
184
|
+
});
|
|
185
|
+
this._frame = frame;
|
|
186
|
+
const shownTickmarks = frame.labelsHidden
|
|
187
|
+
? tickmarks.map((t) => ({...t, text: undefined}))
|
|
188
|
+
: tickmarks;
|
|
189
|
+
|
|
137
190
|
return html`
|
|
138
191
|
<div class="container">
|
|
139
192
|
<obc-watch
|
|
@@ -146,8 +199,8 @@ export class ObcSpeedGauge extends SetpointMixin(LitElement) {
|
|
|
146
199
|
.angleSetpointAtZeroDeadband=${this.setpointAtZeroDeadband}
|
|
147
200
|
.setpointOverride=${this.setpointOverride}
|
|
148
201
|
.animateSetpoint=${this.animateSetpoint}
|
|
149
|
-
.
|
|
150
|
-
.tickmarks=${
|
|
202
|
+
.arcFrame=${frame}
|
|
203
|
+
.tickmarks=${shownTickmarks}
|
|
151
204
|
.tickmarksInside=${this.tickmarksInside}
|
|
152
205
|
.tickmarkStyle=${this.tickmarkStyle}
|
|
153
206
|
.advices=${this._advices}
|
|
@@ -168,7 +221,7 @@ export class ObcSpeedGauge extends SetpointMixin(LitElement) {
|
|
|
168
221
|
},
|
|
169
222
|
]}
|
|
170
223
|
></obc-watch>
|
|
171
|
-
<svg class="rudder" viewBox
|
|
224
|
+
<svg class="rudder" viewBox=${frame.viewBox}>${this.needle}</svg>
|
|
172
225
|
${this.hasReadout
|
|
173
226
|
? html`
|
|
174
227
|
${renderInstrumentReadout({
|