@oicl/openbridge-webcomponents 0.0.15-dev-20240923190011 → 0.0.15-dev-20240923191659

Sign up to get free protection for your applications and to get access to all the features.
Files changed (33) hide show
  1. package/.storybook/main.ts +58 -58
  2. package/.storybook/preview.ts +55 -55
  3. package/custom-elements.json +3 -3
  4. package/dist/navigation-instruments/compass/arrow.js.map +1 -1
  5. package/dist/navigation-instruments/compass/compass.js.map +1 -1
  6. package/dist/navigation-instruments/compass/radial-tickmark.js.map +1 -1
  7. package/dist/navigation-instruments/compass-flat/compass-flat.js.map +1 -1
  8. package/dist/navigation-instruments/thruster/advice.js.map +1 -1
  9. package/dist/navigation-instruments/watch/advice.js.map +1 -1
  10. package/dist/navigation-instruments/watch/label.js.map +1 -1
  11. package/dist/navigation-instruments/watch/watch.js.map +1 -1
  12. package/dist/navigation-instruments/watch-flat/tickmark-flat.js.map +1 -1
  13. package/dist/navigation-instruments/watch-flat/watch-flat.js.map +1 -1
  14. package/dist/svghelpers/rectangular.js.map +1 -1
  15. package/oicl-openbridge-webcomponents-0.0.15-dev-20240923191659.tgz +0 -0
  16. package/package.json +83 -83
  17. package/src/navigation-instruments/compass/arrow.ts +61 -61
  18. package/src/navigation-instruments/compass/compass.stories.ts +37 -37
  19. package/src/navigation-instruments/compass/compass.ts +132 -132
  20. package/src/navigation-instruments/compass/radial-tickmark.ts +77 -77
  21. package/src/navigation-instruments/compass-flat/compass-flat.css +23 -23
  22. package/src/navigation-instruments/compass-flat/compass-flat.stories.ts +35 -35
  23. package/src/navigation-instruments/compass-flat/compass-flat.ts +221 -221
  24. package/src/navigation-instruments/thruster/advice.ts +109 -109
  25. package/src/navigation-instruments/watch/advice.ts +120 -120
  26. package/src/navigation-instruments/watch/label.ts +69 -69
  27. package/src/navigation-instruments/watch/watch.css +11 -11
  28. package/src/navigation-instruments/watch/watch.ts +199 -199
  29. package/src/navigation-instruments/watch-flat/tickmark-flat.ts +62 -62
  30. package/src/navigation-instruments/watch-flat/watch-flat.css +19 -19
  31. package/src/navigation-instruments/watch-flat/watch-flat.stories.ts +17 -17
  32. package/src/navigation-instruments/watch-flat/watch-flat.ts +148 -148
  33. package/src/svghelpers/rectangular.ts +42 -42
@@ -1,221 +1,221 @@
1
- import {LitElement, svg, SVGTemplateResult, unsafeCSS} from 'lit';
2
- import componentStyle from './compass-flat.css?inline';
3
- import {customElement, property} from 'lit/decorators.js';
4
- import {Tickmark, TickmarkType} from '../watch-flat/tickmark-flat';
5
- import '../watch-flat/watch-flat';
6
-
7
- export enum LabelPosition {
8
- top = -45,
9
- bottom = 50,
10
- }
11
-
12
- export enum LabelStyle {
13
- regular = 'var(--instrument-tick-mark-secondary-color)',
14
- }
15
-
16
- export interface Label {
17
- x: number;
18
- y: LabelPosition;
19
- text: string;
20
- }
21
-
22
- @customElement('obc-compass-flat')
23
- export class ObcCompassFlat extends LitElement {
24
- @property({type: Boolean}) noPadding: boolean = true;
25
- @property({type: Boolean}) FOVIndicator: boolean = false;
26
- @property({type: Number}) padding: number = 16;
27
- @property({type: Number}) heading = 0;
28
- @property({type: Number}) courseOverGround = 0;
29
- @property({type: Number}) tickInterval = 5;
30
- @property({type: Number}) FOV = 45;
31
- @property({type: Number}) minFOV = 45;
32
- @property({type: Number}) maxFOV = 180;
33
- labels: Label[] = [];
34
-
35
- @property({type: Number}) containerWidth = 0;
36
-
37
- private resizeObserver: ResizeObserver = new ResizeObserver((entries) => {
38
- for (const entry of entries) {
39
- this.containerWidth = entry.contentRect.width;
40
- this.updateLabels();
41
- }
42
- });
43
-
44
- override connectedCallback() {
45
- super.connectedCallback();
46
- this.resizeObserver.observe(this);
47
- }
48
-
49
- override disconnectedCallback() {
50
- super.disconnectedCallback();
51
- this.resizeObserver.unobserve(this);
52
- }
53
-
54
- private updateLabels() {
55
- if (this.containerWidth < 192) {
56
- this.labels = [];
57
- } else if (this.containerWidth <= 300) {
58
- this.labels = [
59
- {x: -180, y: LabelPosition.top, text: 'S'},
60
- {x: -90, y: LabelPosition.top, text: 'W'},
61
- {x: 0, y: LabelPosition.top, text: 'N'},
62
- {x: 90, y: LabelPosition.top, text: 'E'},
63
- {x: 180, y: LabelPosition.top, text: 'S'},
64
- {x: 270, y: LabelPosition.top, text: 'W'},
65
- {x: 360, y: LabelPosition.top, text: 'N'},
66
- {x: 450, y: LabelPosition.top, text: 'E'},
67
- {x: 540, y: LabelPosition.top, text: 'S'},
68
- ];
69
- } else {
70
- this.labels = [
71
- {x: -180, y: LabelPosition.top, text: 'S'},
72
- {x: -135, y: LabelPosition.top, text: 'SW'},
73
- {x: -90, y: LabelPosition.top, text: 'W'},
74
- {x: -45, y: LabelPosition.top, text: 'NW'},
75
- {x: 0, y: LabelPosition.top, text: 'N'},
76
- {x: 45, y: LabelPosition.top, text: 'NE'},
77
- {x: 90, y: LabelPosition.top, text: 'E'},
78
- {x: 135, y: LabelPosition.top, text: 'SE'},
79
- {x: 180, y: LabelPosition.top, text: 'S'},
80
- {x: 225, y: LabelPosition.top, text: 'SW'},
81
- {x: 270, y: LabelPosition.top, text: 'W'},
82
- {x: 315, y: LabelPosition.top, text: 'NW'},
83
- {x: 360, y: LabelPosition.top, text: 'N'},
84
- {x: 405, y: LabelPosition.top, text: 'NE'},
85
- {x: 450, y: LabelPosition.top, text: 'E'},
86
- {x: 495, y: LabelPosition.top, text: 'SE'},
87
- {x: 540, y: LabelPosition.top, text: 'S'},
88
- ];
89
- }
90
- }
91
-
92
- private generateIntervalTickmarks(scale: number): Tickmark[] {
93
- const tickmarks: Tickmark[] = [];
94
- let cardinalInterval = 90;
95
-
96
- if (this.containerWidth > 300) {
97
- cardinalInterval = 45;
98
- } else if (this.containerWidth < 192) {
99
- cardinalInterval = 0;
100
- }
101
-
102
- for (
103
- let angle = -180;
104
- angle < this.maxFOV * 3;
105
- angle += this.tickInterval
106
- ) {
107
- if (cardinalInterval !== 0 && angle % cardinalInterval === 0) {
108
- continue;
109
- }
110
- tickmarks.push({angle: angle * scale, type: TickmarkType.secondary});
111
- }
112
-
113
- return tickmarks;
114
- }
115
-
116
- private generateCardinalTickmarks(scale: number): Tickmark[] {
117
- const tickmarks: Tickmark[] = [];
118
-
119
- for (const label of this.labels) {
120
- tickmarks.push({angle: label.x * scale, type: TickmarkType.main});
121
- }
122
-
123
- return tickmarks;
124
- }
125
-
126
- private generateTickmarks(scale: number): Tickmark[] {
127
- return [
128
- ...this.generateCardinalTickmarks(scale),
129
- ...this.generateIntervalTickmarks(scale),
130
- ];
131
- }
132
-
133
- private renderFOVIndicator(): SVGTemplateResult[] {
134
- const indicators: SVGTemplateResult[] = [];
135
-
136
- const maxAdjustment = 10;
137
- const minContainerWidth = 300;
138
- const maxContainerWidth = 512;
139
-
140
- let yAdjustment = 0;
141
- if (this.containerWidth < maxContainerWidth) {
142
- const widthRange = maxContainerWidth - minContainerWidth;
143
- const scaleFactor =
144
- (maxContainerWidth - this.containerWidth) / widthRange;
145
- yAdjustment = scaleFactor * maxAdjustment;
146
- }
147
-
148
- const y = LabelPosition.bottom + yAdjustment;
149
-
150
- indicators.push(svg`
151
- <text x="-175" y=${y} class="label left" fill=${LabelStyle.regular}>
152
- ${-this.FOV}\u00B0
153
- </text>`);
154
-
155
- indicators.push(svg`
156
- <text x="0" y=${y} class="label" fill=${LabelStyle.regular}>
157
- ${this.heading}\u00B0
158
- </text>`);
159
-
160
- indicators.push(svg`
161
- <text x="175" y=${y} class="label right" fill=${LabelStyle.regular}>
162
- ${this.FOV}\u00B0
163
- </text>`);
164
-
165
- return indicators;
166
- }
167
-
168
- private get HDGSvg(): SVGTemplateResult {
169
- return svg`<g transform="translate(-24, -74)">
170
- <path d="M36.7011 44.1445L36.6898 44.1379L36.6781 44.1318L24.2301 37.6823L24.0001 37.5631L23.7701 37.6823L11.3221 44.1318L11.3104 44.1379L11.2991 44.1445C9.25497 45.3438 6.78661 43.308 7.68828 41.0919L22.6036 4.43285C23.1096 3.18905 24.8906 3.18905 25.3967 4.43284L40.3119 41.0919C41.2136 43.308 38.7452 45.3438 36.7011 44.1445Z" fill="var(--instrument-enhanced-secondary-color)" stroke="var(--border-silhouette-color)"/>
171
- </g>`;
172
- }
173
-
174
- private COGSvg(translation: number): SVGTemplateResult {
175
- return svg`
176
- <g transform="translate(${-24 + translation}, -74)">
177
- <path d="M31.9025 36.0262L33.1068 36.6502L32.5956 35.3938L24.4632 15.406L24.0001 14.2677L23.537 15.406L15.4046 35.3938L14.8935 36.6502L16.0978 36.0262L24.0001 31.9319L31.9025 36.0262ZM36.7011 44.1445L36.6898 44.1379L36.6781 44.1318L24.2301 37.6823L24.0001 37.5631L23.7701 37.6823L11.3221 44.1318L11.3104 44.1379L11.2991 44.1445C9.25497 45.3438 6.78661 43.308 7.68828 41.0919L22.6036 4.43285C23.1096 3.18905 24.8906 3.18905 25.3967 4.43284L40.3119 41.0919C41.2136 43.308 38.7452 45.3438 36.7011 44.1445Z" fill="var(--instrument-enhanced-secondary-color)" stroke="var(--border-silhouette-color)"/>
178
- </g>
179
- `;
180
- }
181
-
182
- override render() {
183
- let angleDiff = this.courseOverGround - this.heading;
184
-
185
- if (angleDiff > this.maxFOV) {
186
- angleDiff -= 360;
187
- } else if (angleDiff < -this.maxFOV) {
188
- angleDiff += 360;
189
- }
190
-
191
- this.FOV = Math.max(this.minFOV, Math.abs(angleDiff));
192
-
193
- const baseOffset = 5;
194
- const translationScale = (baseOffset * 35) / this.FOV;
195
-
196
- const translation = angleDiff * translationScale;
197
-
198
- const tickmarks = this.generateTickmarks(translationScale);
199
- this.labels.map((l) => {
200
- l.x = l.x * translationScale;
201
- });
202
-
203
- const viewBox = this.noPadding ? '-192 -128 384 128' : '-200 -144 400 144';
204
-
205
- return svg`
206
- <div class="container">
207
- <obc-watch-flat .noPadding=${this.noPadding} .FOVIndicator=${this.FOVIndicator ? this.renderFOVIndicator() : []} .labels=${this.labels} .rotation=${this.heading} .tickmarks=${tickmarks} .tickmarkSpacing=${translationScale}></obc-watch-flat>
208
- <svg viewBox=${viewBox} xmlns="http://www.w3.org/2000/svg">
209
- ${this.HDGSvg}${this.COGSvg(translation)}
210
- </div>
211
- `;
212
- }
213
-
214
- static override styles = unsafeCSS(componentStyle);
215
- }
216
-
217
- declare global {
218
- interface HTMLElementTagNameMap {
219
- 'obc-compass-flat': ObcCompassFlat;
220
- }
221
- }
1
+ import {LitElement, svg, SVGTemplateResult, unsafeCSS} from 'lit';
2
+ import componentStyle from './compass-flat.css?inline';
3
+ import {customElement, property} from 'lit/decorators.js';
4
+ import {Tickmark, TickmarkType} from '../watch-flat/tickmark-flat';
5
+ import '../watch-flat/watch-flat';
6
+
7
+ export enum LabelPosition {
8
+ top = -45,
9
+ bottom = 50,
10
+ }
11
+
12
+ export enum LabelStyle {
13
+ regular = 'var(--instrument-tick-mark-secondary-color)',
14
+ }
15
+
16
+ export interface Label {
17
+ x: number;
18
+ y: LabelPosition;
19
+ text: string;
20
+ }
21
+
22
+ @customElement('obc-compass-flat')
23
+ export class ObcCompassFlat extends LitElement {
24
+ @property({type: Boolean}) noPadding: boolean = true;
25
+ @property({type: Boolean}) FOVIndicator: boolean = false;
26
+ @property({type: Number}) padding: number = 16;
27
+ @property({type: Number}) heading = 0;
28
+ @property({type: Number}) courseOverGround = 0;
29
+ @property({type: Number}) tickInterval = 5;
30
+ @property({type: Number}) FOV = 45;
31
+ @property({type: Number}) minFOV = 45;
32
+ @property({type: Number}) maxFOV = 180;
33
+ labels: Label[] = [];
34
+
35
+ @property({type: Number}) containerWidth = 0;
36
+
37
+ private resizeObserver: ResizeObserver = new ResizeObserver((entries) => {
38
+ for (const entry of entries) {
39
+ this.containerWidth = entry.contentRect.width;
40
+ this.updateLabels();
41
+ }
42
+ });
43
+
44
+ override connectedCallback() {
45
+ super.connectedCallback();
46
+ this.resizeObserver.observe(this);
47
+ }
48
+
49
+ override disconnectedCallback() {
50
+ super.disconnectedCallback();
51
+ this.resizeObserver.unobserve(this);
52
+ }
53
+
54
+ private updateLabels() {
55
+ if (this.containerWidth < 192) {
56
+ this.labels = [];
57
+ } else if (this.containerWidth <= 300) {
58
+ this.labels = [
59
+ {x: -180, y: LabelPosition.top, text: 'S'},
60
+ {x: -90, y: LabelPosition.top, text: 'W'},
61
+ {x: 0, y: LabelPosition.top, text: 'N'},
62
+ {x: 90, y: LabelPosition.top, text: 'E'},
63
+ {x: 180, y: LabelPosition.top, text: 'S'},
64
+ {x: 270, y: LabelPosition.top, text: 'W'},
65
+ {x: 360, y: LabelPosition.top, text: 'N'},
66
+ {x: 450, y: LabelPosition.top, text: 'E'},
67
+ {x: 540, y: LabelPosition.top, text: 'S'},
68
+ ];
69
+ } else {
70
+ this.labels = [
71
+ {x: -180, y: LabelPosition.top, text: 'S'},
72
+ {x: -135, y: LabelPosition.top, text: 'SW'},
73
+ {x: -90, y: LabelPosition.top, text: 'W'},
74
+ {x: -45, y: LabelPosition.top, text: 'NW'},
75
+ {x: 0, y: LabelPosition.top, text: 'N'},
76
+ {x: 45, y: LabelPosition.top, text: 'NE'},
77
+ {x: 90, y: LabelPosition.top, text: 'E'},
78
+ {x: 135, y: LabelPosition.top, text: 'SE'},
79
+ {x: 180, y: LabelPosition.top, text: 'S'},
80
+ {x: 225, y: LabelPosition.top, text: 'SW'},
81
+ {x: 270, y: LabelPosition.top, text: 'W'},
82
+ {x: 315, y: LabelPosition.top, text: 'NW'},
83
+ {x: 360, y: LabelPosition.top, text: 'N'},
84
+ {x: 405, y: LabelPosition.top, text: 'NE'},
85
+ {x: 450, y: LabelPosition.top, text: 'E'},
86
+ {x: 495, y: LabelPosition.top, text: 'SE'},
87
+ {x: 540, y: LabelPosition.top, text: 'S'},
88
+ ];
89
+ }
90
+ }
91
+
92
+ private generateIntervalTickmarks(scale: number): Tickmark[] {
93
+ const tickmarks: Tickmark[] = [];
94
+ let cardinalInterval = 90;
95
+
96
+ if (this.containerWidth > 300) {
97
+ cardinalInterval = 45;
98
+ } else if (this.containerWidth < 192) {
99
+ cardinalInterval = 0;
100
+ }
101
+
102
+ for (
103
+ let angle = -180;
104
+ angle < this.maxFOV * 3;
105
+ angle += this.tickInterval
106
+ ) {
107
+ if (cardinalInterval !== 0 && angle % cardinalInterval === 0) {
108
+ continue;
109
+ }
110
+ tickmarks.push({angle: angle * scale, type: TickmarkType.secondary});
111
+ }
112
+
113
+ return tickmarks;
114
+ }
115
+
116
+ private generateCardinalTickmarks(scale: number): Tickmark[] {
117
+ const tickmarks: Tickmark[] = [];
118
+
119
+ for (const label of this.labels) {
120
+ tickmarks.push({angle: label.x * scale, type: TickmarkType.main});
121
+ }
122
+
123
+ return tickmarks;
124
+ }
125
+
126
+ private generateTickmarks(scale: number): Tickmark[] {
127
+ return [
128
+ ...this.generateCardinalTickmarks(scale),
129
+ ...this.generateIntervalTickmarks(scale),
130
+ ];
131
+ }
132
+
133
+ private renderFOVIndicator(): SVGTemplateResult[] {
134
+ const indicators: SVGTemplateResult[] = [];
135
+
136
+ const maxAdjustment = 10;
137
+ const minContainerWidth = 300;
138
+ const maxContainerWidth = 512;
139
+
140
+ let yAdjustment = 0;
141
+ if (this.containerWidth < maxContainerWidth) {
142
+ const widthRange = maxContainerWidth - minContainerWidth;
143
+ const scaleFactor =
144
+ (maxContainerWidth - this.containerWidth) / widthRange;
145
+ yAdjustment = scaleFactor * maxAdjustment;
146
+ }
147
+
148
+ const y = LabelPosition.bottom + yAdjustment;
149
+
150
+ indicators.push(svg`
151
+ <text x="-175" y=${y} class="label left" fill=${LabelStyle.regular}>
152
+ ${-this.FOV}\u00B0
153
+ </text>`);
154
+
155
+ indicators.push(svg`
156
+ <text x="0" y=${y} class="label" fill=${LabelStyle.regular}>
157
+ ${this.heading}\u00B0
158
+ </text>`);
159
+
160
+ indicators.push(svg`
161
+ <text x="175" y=${y} class="label right" fill=${LabelStyle.regular}>
162
+ ${this.FOV}\u00B0
163
+ </text>`);
164
+
165
+ return indicators;
166
+ }
167
+
168
+ private get HDGSvg(): SVGTemplateResult {
169
+ return svg`<g transform="translate(-24, -74)">
170
+ <path d="M36.7011 44.1445L36.6898 44.1379L36.6781 44.1318L24.2301 37.6823L24.0001 37.5631L23.7701 37.6823L11.3221 44.1318L11.3104 44.1379L11.2991 44.1445C9.25497 45.3438 6.78661 43.308 7.68828 41.0919L22.6036 4.43285C23.1096 3.18905 24.8906 3.18905 25.3967 4.43284L40.3119 41.0919C41.2136 43.308 38.7452 45.3438 36.7011 44.1445Z" fill="var(--instrument-enhanced-secondary-color)" stroke="var(--border-silhouette-color)"/>
171
+ </g>`;
172
+ }
173
+
174
+ private COGSvg(translation: number): SVGTemplateResult {
175
+ return svg`
176
+ <g transform="translate(${-24 + translation}, -74)">
177
+ <path d="M31.9025 36.0262L33.1068 36.6502L32.5956 35.3938L24.4632 15.406L24.0001 14.2677L23.537 15.406L15.4046 35.3938L14.8935 36.6502L16.0978 36.0262L24.0001 31.9319L31.9025 36.0262ZM36.7011 44.1445L36.6898 44.1379L36.6781 44.1318L24.2301 37.6823L24.0001 37.5631L23.7701 37.6823L11.3221 44.1318L11.3104 44.1379L11.2991 44.1445C9.25497 45.3438 6.78661 43.308 7.68828 41.0919L22.6036 4.43285C23.1096 3.18905 24.8906 3.18905 25.3967 4.43284L40.3119 41.0919C41.2136 43.308 38.7452 45.3438 36.7011 44.1445Z" fill="var(--instrument-enhanced-secondary-color)" stroke="var(--border-silhouette-color)"/>
178
+ </g>
179
+ `;
180
+ }
181
+
182
+ override render() {
183
+ let angleDiff = this.courseOverGround - this.heading;
184
+
185
+ if (angleDiff > this.maxFOV) {
186
+ angleDiff -= 360;
187
+ } else if (angleDiff < -this.maxFOV) {
188
+ angleDiff += 360;
189
+ }
190
+
191
+ this.FOV = Math.max(this.minFOV, Math.abs(angleDiff));
192
+
193
+ const baseOffset = 5;
194
+ const translationScale = (baseOffset * 35) / this.FOV;
195
+
196
+ const translation = angleDiff * translationScale;
197
+
198
+ const tickmarks = this.generateTickmarks(translationScale);
199
+ this.labels.map((l) => {
200
+ l.x = l.x * translationScale;
201
+ });
202
+
203
+ const viewBox = this.noPadding ? '-192 -128 384 128' : '-200 -144 400 144';
204
+
205
+ return svg`
206
+ <div class="container">
207
+ <obc-watch-flat .noPadding=${this.noPadding} .FOVIndicator=${this.FOVIndicator ? this.renderFOVIndicator() : []} .labels=${this.labels} .rotation=${this.heading} .tickmarks=${tickmarks} .tickmarkSpacing=${translationScale}></obc-watch-flat>
208
+ <svg viewBox=${viewBox} xmlns="http://www.w3.org/2000/svg">
209
+ ${this.HDGSvg}${this.COGSvg(translation)}
210
+ </div>
211
+ `;
212
+ }
213
+
214
+ static override styles = unsafeCSS(componentStyle);
215
+ }
216
+
217
+ declare global {
218
+ interface HTMLElementTagNameMap {
219
+ 'obc-compass-flat': ObcCompassFlat;
220
+ }
221
+ }
@@ -1,109 +1,109 @@
1
- import {SVGTemplateResult, nothing, svg} from 'lit';
2
- import {AdviceState, AdviceType} from '../watch/advice';
3
- import {TickmarkStyle} from '../watch/tickmark';
4
- import {singleSidedTickmark} from './tickmark';
5
-
6
- export interface LinearAdviceRaw {
7
- min: number;
8
- max: number;
9
- type: AdviceType;
10
- state: AdviceState;
11
- }
12
-
13
- export interface LinearAdvice {
14
- min: number;
15
- max: number;
16
- type: AdviceType;
17
- hinted: boolean;
18
- }
19
-
20
- function adviceMask(
21
- height: number,
22
- min: number,
23
- max: number,
24
- fill: string,
25
- stroke: string
26
- ): SVGTemplateResult {
27
- const width = 8;
28
- const x1 = 12;
29
- const x2 = x1 + width;
30
- const r = width / 2;
31
- const yL = (-min * height) / 100 - 2 * r - 2;
32
- const yH = (-max * height) / 100 + 2 * r - 2;
33
-
34
- const path = `M ${x1} ${yL}
35
- A ${r} ${r} 0 0 0 ${x2} ${yL}
36
- V ${yH}
37
- A ${r} ${r} 0 0 0 ${x1} ${yH}
38
- Z`;
39
- return svg`<path d=${path} fill=${fill} stroke=${stroke} stroke-width="1" vector-effect="non-scaling-stroke" />`;
40
- }
41
-
42
- export function renderAdvice(
43
- height: number,
44
- advice: LinearAdviceRaw,
45
- flipDirection: boolean
46
- ): SVGTemplateResult {
47
- if (advice.type === AdviceType.caution) {
48
- let mainColor;
49
- let fillColor: string | null = null;
50
- if (advice.state === AdviceState.hinted) {
51
- mainColor = 'var(--instrument-frame-tertiary-color)';
52
- } else if (advice.state === AdviceState.regular) {
53
- mainColor = 'var(--instrument-tick-mark-tertiary-color)';
54
- } else {
55
- mainColor = 'var(--on-caution-active-color)';
56
- fillColor = 'var(--alert-caution-color)';
57
- }
58
- const pattern = [];
59
- const ypattern = flipDirection ? 50 : -50;
60
- for (let i = -100; i < 300; i += 16) {
61
- pattern.push(svg`<g transform="translate(0 ${-i}) ">
62
- <path d="M 50 0 L 0 ${ypattern}" stroke=${mainColor} stroke-width="6"/>
63
- </g>
64
- `);
65
- }
66
- const maskId = `adviceMask-${advice.min}-${advice.max}`;
67
- let tickmarkStyle = TickmarkStyle.hinted;
68
- if (advice.state === AdviceState.regular) {
69
- tickmarkStyle = TickmarkStyle.regular;
70
- } else if (advice.state === AdviceState.triggered) {
71
- tickmarkStyle = TickmarkStyle.enhanced;
72
- }
73
-
74
- return svg`
75
- <mask id=${maskId}>
76
- ${adviceMask(height, advice.min, advice.max, 'white', 'black')}
77
- </mask>
78
- <g mask="url(#${maskId})">
79
- ${fillColor ? svg`<rect x="-256" y="-512" width="512" height="1024" fill="${fillColor}"/>` : nothing}
80
- ${pattern}
81
- </g>
82
- ${adviceMask(height, advice.min, advice.max, 'none', mainColor)}
83
- ${singleSidedTickmark(height, advice.min, tickmarkStyle)}
84
- ${singleSidedTickmark(height, advice.max, tickmarkStyle)}
85
- `;
86
- } else {
87
- let strokeColor;
88
- let tickmarkStyle;
89
- let fillColor: string;
90
- if (advice.state === AdviceState.hinted) {
91
- strokeColor = 'var(--instrument-frame-tertiary-color)';
92
- fillColor = 'none';
93
- tickmarkStyle = TickmarkStyle.hinted;
94
- } else if (advice.state === AdviceState.regular) {
95
- strokeColor = 'var(--instrument-regular-secondary-color)';
96
- fillColor = 'none';
97
- tickmarkStyle = TickmarkStyle.regular;
98
- } else {
99
- strokeColor = 'var(--instrument-enhanced-secondary-color)';
100
- fillColor = strokeColor;
101
- tickmarkStyle = TickmarkStyle.regular;
102
- }
103
- return svg`
104
- ${adviceMask(height, advice.min, advice.max, fillColor, strokeColor)}
105
- ${singleSidedTickmark(height, advice.min, tickmarkStyle)}
106
- ${singleSidedTickmark(height, advice.max, tickmarkStyle)}
107
- `;
108
- }
109
- }
1
+ import {SVGTemplateResult, nothing, svg} from 'lit';
2
+ import {AdviceState, AdviceType} from '../watch/advice';
3
+ import {TickmarkStyle} from '../watch/tickmark';
4
+ import {singleSidedTickmark} from './tickmark';
5
+
6
+ export interface LinearAdviceRaw {
7
+ min: number;
8
+ max: number;
9
+ type: AdviceType;
10
+ state: AdviceState;
11
+ }
12
+
13
+ export interface LinearAdvice {
14
+ min: number;
15
+ max: number;
16
+ type: AdviceType;
17
+ hinted: boolean;
18
+ }
19
+
20
+ function adviceMask(
21
+ height: number,
22
+ min: number,
23
+ max: number,
24
+ fill: string,
25
+ stroke: string
26
+ ): SVGTemplateResult {
27
+ const width = 8;
28
+ const x1 = 12;
29
+ const x2 = x1 + width;
30
+ const r = width / 2;
31
+ const yL = (-min * height) / 100 - 2 * r - 2;
32
+ const yH = (-max * height) / 100 + 2 * r - 2;
33
+
34
+ const path = `M ${x1} ${yL}
35
+ A ${r} ${r} 0 0 0 ${x2} ${yL}
36
+ V ${yH}
37
+ A ${r} ${r} 0 0 0 ${x1} ${yH}
38
+ Z`;
39
+ return svg`<path d=${path} fill=${fill} stroke=${stroke} stroke-width="1" vector-effect="non-scaling-stroke" />`;
40
+ }
41
+
42
+ export function renderAdvice(
43
+ height: number,
44
+ advice: LinearAdviceRaw,
45
+ flipDirection: boolean
46
+ ): SVGTemplateResult {
47
+ if (advice.type === AdviceType.caution) {
48
+ let mainColor;
49
+ let fillColor: string | null = null;
50
+ if (advice.state === AdviceState.hinted) {
51
+ mainColor = 'var(--instrument-frame-tertiary-color)';
52
+ } else if (advice.state === AdviceState.regular) {
53
+ mainColor = 'var(--instrument-tick-mark-tertiary-color)';
54
+ } else {
55
+ mainColor = 'var(--on-caution-active-color)';
56
+ fillColor = 'var(--alert-caution-color)';
57
+ }
58
+ const pattern = [];
59
+ const ypattern = flipDirection ? 50 : -50;
60
+ for (let i = -100; i < 300; i += 16) {
61
+ pattern.push(svg`<g transform="translate(0 ${-i}) ">
62
+ <path d="M 50 0 L 0 ${ypattern}" stroke=${mainColor} stroke-width="6"/>
63
+ </g>
64
+ `);
65
+ }
66
+ const maskId = `adviceMask-${advice.min}-${advice.max}`;
67
+ let tickmarkStyle = TickmarkStyle.hinted;
68
+ if (advice.state === AdviceState.regular) {
69
+ tickmarkStyle = TickmarkStyle.regular;
70
+ } else if (advice.state === AdviceState.triggered) {
71
+ tickmarkStyle = TickmarkStyle.enhanced;
72
+ }
73
+
74
+ return svg`
75
+ <mask id=${maskId}>
76
+ ${adviceMask(height, advice.min, advice.max, 'white', 'black')}
77
+ </mask>
78
+ <g mask="url(#${maskId})">
79
+ ${fillColor ? svg`<rect x="-256" y="-512" width="512" height="1024" fill="${fillColor}"/>` : nothing}
80
+ ${pattern}
81
+ </g>
82
+ ${adviceMask(height, advice.min, advice.max, 'none', mainColor)}
83
+ ${singleSidedTickmark(height, advice.min, tickmarkStyle)}
84
+ ${singleSidedTickmark(height, advice.max, tickmarkStyle)}
85
+ `;
86
+ } else {
87
+ let strokeColor;
88
+ let tickmarkStyle;
89
+ let fillColor: string;
90
+ if (advice.state === AdviceState.hinted) {
91
+ strokeColor = 'var(--instrument-frame-tertiary-color)';
92
+ fillColor = 'none';
93
+ tickmarkStyle = TickmarkStyle.hinted;
94
+ } else if (advice.state === AdviceState.regular) {
95
+ strokeColor = 'var(--instrument-regular-secondary-color)';
96
+ fillColor = 'none';
97
+ tickmarkStyle = TickmarkStyle.regular;
98
+ } else {
99
+ strokeColor = 'var(--instrument-enhanced-secondary-color)';
100
+ fillColor = strokeColor;
101
+ tickmarkStyle = TickmarkStyle.regular;
102
+ }
103
+ return svg`
104
+ ${adviceMask(height, advice.min, advice.max, fillColor, strokeColor)}
105
+ ${singleSidedTickmark(height, advice.min, tickmarkStyle)}
106
+ ${singleSidedTickmark(height, advice.max, tickmarkStyle)}
107
+ `;
108
+ }
109
+ }