@oicl/openbridge-webcomponents 0.0.15-dev-20240916185711 → 0.0.15-dev-20240923190011
Sign up to get free protection for your applications and to get access to all the features.
- package/.storybook/main.ts +8 -0
- package/.storybook/preview.ts +2 -0
- package/__snapshots__/building-blocks-watch--advice.png +0 -0
- package/__snapshots__/building-blocks-watch-flat--primary.png +0 -0
- package/__snapshots__/navigation-instruments-azimuth-thruster--in-command.png +0 -0
- package/__snapshots__/navigation-instruments-azimuth-thruster-labeled--large.png +0 -0
- package/__snapshots__/navigation-instruments-azimuth-thruster-labeled--medium.png +0 -0
- package/__snapshots__/navigation-instruments-azimuth-thruster-labeled--no-command.png +0 -0
- package/__snapshots__/navigation-instruments-compass--primary.png +0 -0
- package/__snapshots__/navigation-instruments-compass-flat--primary.png +0 -0
- package/__snapshots__/navigation-instruments-compass-flat--with-fov-indicator.png +0 -0
- package/custom-elements.json +968 -7
- package/dist/navigation-instruments/compass/arrow.d.ts +7 -0
- package/dist/navigation-instruments/compass/arrow.d.ts.map +1 -0
- package/dist/navigation-instruments/compass/arrow.js +59 -0
- package/dist/navigation-instruments/compass/arrow.js.map +1 -0
- package/dist/navigation-instruments/compass/compass.d.ts +23 -0
- package/dist/navigation-instruments/compass/compass.d.ts.map +1 -0
- package/dist/navigation-instruments/compass/compass.js +139 -0
- package/dist/navigation-instruments/compass/compass.js.map +1 -0
- package/dist/navigation-instruments/compass/radial-tickmark.d.ts +4 -0
- package/dist/navigation-instruments/compass/radial-tickmark.d.ts.map +1 -0
- package/dist/navigation-instruments/compass/radial-tickmark.js +69 -0
- package/dist/navigation-instruments/compass/radial-tickmark.js.map +1 -0
- package/dist/navigation-instruments/compass-flat/compass-flat.css.js +29 -0
- package/dist/navigation-instruments/compass-flat/compass-flat.css.js.map +1 -0
- package/dist/navigation-instruments/compass-flat/compass-flat.d.ts +45 -0
- package/dist/navigation-instruments/compass-flat/compass-flat.d.ts.map +1 -0
- package/dist/navigation-instruments/compass-flat/compass-flat.js +223 -0
- package/dist/navigation-instruments/compass-flat/compass-flat.js.map +1 -0
- package/dist/navigation-instruments/thruster/advice.d.ts.map +1 -1
- package/dist/navigation-instruments/thruster/advice.js +9 -5
- package/dist/navigation-instruments/thruster/advice.js.map +1 -1
- package/dist/navigation-instruments/watch/advice.js +1 -1
- package/dist/navigation-instruments/watch/advice.js.map +1 -1
- package/dist/navigation-instruments/watch/label.d.ts +3 -0
- package/dist/navigation-instruments/watch/label.d.ts.map +1 -0
- package/dist/navigation-instruments/watch/label.js +68 -0
- package/dist/navigation-instruments/watch/label.js.map +1 -0
- package/dist/navigation-instruments/watch/watch.css.js +15 -14
- package/dist/navigation-instruments/watch/watch.css.js.map +1 -1
- package/dist/navigation-instruments/watch/watch.d.ts +3 -0
- package/dist/navigation-instruments/watch/watch.d.ts.map +1 -1
- package/dist/navigation-instruments/watch/watch.js +34 -1
- package/dist/navigation-instruments/watch/watch.js.map +1 -1
- package/dist/navigation-instruments/watch-flat/tickmark-flat.d.ts +20 -0
- package/dist/navigation-instruments/watch-flat/tickmark-flat.d.ts.map +1 -0
- package/dist/navigation-instruments/watch-flat/tickmark-flat.js +53 -0
- package/dist/navigation-instruments/watch-flat/tickmark-flat.js.map +1 -0
- package/dist/navigation-instruments/watch-flat/watch-flat.css.js +32 -0
- package/dist/navigation-instruments/watch-flat/watch-flat.css.js.map +1 -0
- package/dist/navigation-instruments/watch-flat/watch-flat.d.ts +29 -0
- package/dist/navigation-instruments/watch-flat/watch-flat.d.ts.map +1 -0
- package/dist/navigation-instruments/watch-flat/watch-flat.js +184 -0
- package/dist/navigation-instruments/watch-flat/watch-flat.js.map +1 -0
- package/dist/svghelpers/rectangular.d.ts +1 -0
- package/dist/svghelpers/rectangular.d.ts.map +1 -1
- package/dist/svghelpers/rectangular.js +3 -2
- package/dist/svghelpers/rectangular.js.map +1 -1
- package/package.json +16 -11
- package/src/navigation-instruments/compass/arrow.ts +61 -0
- package/src/navigation-instruments/compass/compass.stories.ts +37 -0
- package/src/navigation-instruments/compass/compass.ts +132 -0
- package/src/navigation-instruments/compass/radial-tickmark.ts +77 -0
- package/src/navigation-instruments/compass-flat/compass-flat.css +23 -0
- package/src/navigation-instruments/compass-flat/compass-flat.stories.ts +35 -0
- package/src/navigation-instruments/compass-flat/compass-flat.ts +221 -0
- package/src/navigation-instruments/thruster/advice.ts +9 -5
- package/src/navigation-instruments/watch/advice.ts +1 -1
- package/src/navigation-instruments/watch/label.ts +69 -0
- package/src/navigation-instruments/watch/watch.css +7 -7
- package/src/navigation-instruments/watch/watch.ts +30 -1
- package/src/navigation-instruments/watch-flat/tickmark-flat.ts +62 -0
- package/src/navigation-instruments/watch-flat/watch-flat.css +19 -0
- package/src/navigation-instruments/watch-flat/watch-flat.stories.ts +17 -0
- package/src/navigation-instruments/watch-flat/watch-flat.ts +148 -0
- package/src/svghelpers/rectangular.ts +6 -3
@@ -0,0 +1,184 @@
|
|
1
|
+
import { unsafeCSS, LitElement, svg, html } from "lit";
|
2
|
+
import { property, customElement } from "lit/decorators.js";
|
3
|
+
import compentStyle from "./watch-flat.css.js";
|
4
|
+
import { tickmark, TickmarkStyle } from "./tickmark-flat.js";
|
5
|
+
import { rect } from "../../svghelpers/rectangular.js";
|
6
|
+
var __defProp = Object.defineProperty;
|
7
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
8
|
+
var __decorateClass = (decorators, target, key, kind) => {
|
9
|
+
var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
|
10
|
+
for (var i = decorators.length - 1, decorator; i >= 0; i--)
|
11
|
+
if (decorator = decorators[i])
|
12
|
+
result = (kind ? decorator(target, key, result) : decorator(result)) || result;
|
13
|
+
if (kind && result)
|
14
|
+
__defProp(target, key, result);
|
15
|
+
return result;
|
16
|
+
};
|
17
|
+
let ObcWatchFlat = class extends LitElement {
|
18
|
+
constructor() {
|
19
|
+
super(...arguments);
|
20
|
+
this.width = 352;
|
21
|
+
this.height = 72;
|
22
|
+
this.padding = 0;
|
23
|
+
this.rotation = 0;
|
24
|
+
this.tickmarkSpacing = 0;
|
25
|
+
this.tickmarks = [];
|
26
|
+
this.labels = [];
|
27
|
+
this.FOVIndicator = [];
|
28
|
+
this.trackHeight = 2 / 3 * this.height;
|
29
|
+
this.ticksHeight = this.height - this.trackHeight;
|
30
|
+
this.borderRadius = 8;
|
31
|
+
}
|
32
|
+
renderClipPath(offsetY = 0) {
|
33
|
+
return svg`
|
34
|
+
<clipPath id="frameClipPath${offsetY === 0 ? "" : "Tickmarks"}">
|
35
|
+
<rect x="${-this.width / 2}" y="${-this.height / 2 + offsetY}"
|
36
|
+
width="${this.width}" height="${this.height}"
|
37
|
+
rx="${this.borderRadius}" />
|
38
|
+
</clipPath>
|
39
|
+
`;
|
40
|
+
}
|
41
|
+
renderLabelMask() {
|
42
|
+
return svg`
|
43
|
+
<mask id="labelMask">
|
44
|
+
<rect x="${-this.width / 2}" y="${-70}"
|
45
|
+
width="${this.width}" height="${32}"
|
46
|
+
/>
|
47
|
+
<linearGradient id="fadeGradient" gradientUnits="userSpaceOnUse"
|
48
|
+
x1="${-this.width / 2}" y1="0" x2="${this.width / 2}" y2="0">
|
49
|
+
<stop offset="0%" style="stop-color:black; stop-opacity:1;" />
|
50
|
+
<stop offset="10%" style="stop-color:white; stop-opacity:1;" />
|
51
|
+
<stop offset="50%" style="stop-color:white; stop-opacity:1;" />
|
52
|
+
<stop offset="90%" style="stop-color:white; stop-opacity:1;" />
|
53
|
+
<stop offset="100%" style="stop-color:black; stop-opacity:1;" />
|
54
|
+
</linearGradient>
|
55
|
+
<rect x="${-this.width / 2}" y="${-70}"
|
56
|
+
width="${this.width}" height="${32}"
|
57
|
+
fill="url(#fadeGradient)" />
|
58
|
+
</mask>
|
59
|
+
`;
|
60
|
+
}
|
61
|
+
renderLabels(scale) {
|
62
|
+
const labels = [];
|
63
|
+
for (const l of this.labels) {
|
64
|
+
labels.push(
|
65
|
+
svg`<g transform="translate(${-this.rotation * this.tickmarkSpacing}, ${-6 / scale})">
|
66
|
+
<text x=${l.x} y=${l.y} class="label" fill=${"var(--instrument-tick-mark-secondary-color)"}>
|
67
|
+
${l.text}
|
68
|
+
</text>
|
69
|
+
</g>`
|
70
|
+
);
|
71
|
+
}
|
72
|
+
return labels;
|
73
|
+
}
|
74
|
+
watchFace() {
|
75
|
+
const strokeWidth = 1;
|
76
|
+
return svg`
|
77
|
+
${this.renderClipPath()}
|
78
|
+
${this.renderClipPath(-40)}
|
79
|
+
<g clip-path="url(#frameClipPath)">
|
80
|
+
${rect("frame-track", {
|
81
|
+
width: this.width,
|
82
|
+
height: this.trackHeight,
|
83
|
+
y: this.height / 2 - this.trackHeight,
|
84
|
+
strokeWidth,
|
85
|
+
strokeColor: "var(--instrument-frame-secondary-color)",
|
86
|
+
strokePosition: "inside",
|
87
|
+
fillColor: "var(--instrument-frame-secondary-color)",
|
88
|
+
borderRadius: 0
|
89
|
+
})}
|
90
|
+
${rect("frame-ticks", {
|
91
|
+
width: this.width,
|
92
|
+
height: this.ticksHeight,
|
93
|
+
y: this.height / 2 - this.trackHeight - this.ticksHeight,
|
94
|
+
strokeWidth,
|
95
|
+
strokeColor: "var(--instrument-frame-primary-color)",
|
96
|
+
strokePosition: "inside",
|
97
|
+
fillColor: "var(--instrument-frame-primary-color)",
|
98
|
+
borderRadius: 0
|
99
|
+
})}
|
100
|
+
</g>
|
101
|
+
${rect("frame-outline", {
|
102
|
+
width: this.width,
|
103
|
+
height: this.height,
|
104
|
+
strokeWidth,
|
105
|
+
strokeColor: "var(--instrument-frame-tertiary-color)",
|
106
|
+
strokePosition: "inside",
|
107
|
+
fillColor: "none",
|
108
|
+
borderRadius: this.borderRadius
|
109
|
+
})}
|
110
|
+
`;
|
111
|
+
}
|
112
|
+
render() {
|
113
|
+
const width = (this.width / 2 + this.padding) * 2;
|
114
|
+
const viewBox = `-${width / 2} -${this.height / 2} ${width} ${this.height}`;
|
115
|
+
const scale = this.clientWidth / width;
|
116
|
+
return html`
|
117
|
+
<svg
|
118
|
+
width="100%"
|
119
|
+
height="100%"
|
120
|
+
viewBox=${viewBox}
|
121
|
+
style="--scale: ${scale}"
|
122
|
+
>
|
123
|
+
${this.watchFace()} ${this.renderLabelMask()} ${this.FOVIndicator}
|
124
|
+
|
125
|
+
<g clip-path="url(#frameClipPath)">
|
126
|
+
${this.tickmarks.map(
|
127
|
+
(t) => svg`
|
128
|
+
<g transform="translate(${-this.rotation * this.tickmarkSpacing}, 0)">
|
129
|
+
${tickmark(t.angle, t.type, TickmarkStyle.hinted)}
|
130
|
+
</g>
|
131
|
+
`
|
132
|
+
)}
|
133
|
+
</g>
|
134
|
+
|
135
|
+
<g mask="url(#labelMask)">
|
136
|
+
${this.renderLabels(scale)}
|
137
|
+
</svg>
|
138
|
+
`;
|
139
|
+
}
|
140
|
+
};
|
141
|
+
ObcWatchFlat.styles = unsafeCSS(compentStyle);
|
142
|
+
__decorateClass([
|
143
|
+
property({ type: Number })
|
144
|
+
], ObcWatchFlat.prototype, "width", 2);
|
145
|
+
__decorateClass([
|
146
|
+
property({ type: Number })
|
147
|
+
], ObcWatchFlat.prototype, "height", 2);
|
148
|
+
__decorateClass([
|
149
|
+
property({ type: Number })
|
150
|
+
], ObcWatchFlat.prototype, "padding", 2);
|
151
|
+
__decorateClass([
|
152
|
+
property({ type: Number })
|
153
|
+
], ObcWatchFlat.prototype, "rotation", 2);
|
154
|
+
__decorateClass([
|
155
|
+
property({ type: Number })
|
156
|
+
], ObcWatchFlat.prototype, "tickmarkSpacing", 2);
|
157
|
+
__decorateClass([
|
158
|
+
property({ type: Number })
|
159
|
+
], ObcWatchFlat.prototype, "angleSetpoint", 2);
|
160
|
+
__decorateClass([
|
161
|
+
property({ type: Array, attribute: false })
|
162
|
+
], ObcWatchFlat.prototype, "tickmarks", 2);
|
163
|
+
__decorateClass([
|
164
|
+
property({ type: Array, attribute: false })
|
165
|
+
], ObcWatchFlat.prototype, "labels", 2);
|
166
|
+
__decorateClass([
|
167
|
+
property({ type: Array, attribute: false })
|
168
|
+
], ObcWatchFlat.prototype, "FOVIndicator", 2);
|
169
|
+
__decorateClass([
|
170
|
+
property({ type: Number })
|
171
|
+
], ObcWatchFlat.prototype, "trackHeight", 2);
|
172
|
+
__decorateClass([
|
173
|
+
property({ type: Number })
|
174
|
+
], ObcWatchFlat.prototype, "ticksHeight", 2);
|
175
|
+
__decorateClass([
|
176
|
+
property({ type: Number })
|
177
|
+
], ObcWatchFlat.prototype, "borderRadius", 2);
|
178
|
+
ObcWatchFlat = __decorateClass([
|
179
|
+
customElement("obc-watch-flat")
|
180
|
+
], ObcWatchFlat);
|
181
|
+
export {
|
182
|
+
ObcWatchFlat
|
183
|
+
};
|
184
|
+
//# sourceMappingURL=watch-flat.js.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"watch-flat.js","sources":["../../../src/navigation-instruments/watch-flat/watch-flat.ts"],"sourcesContent":["import {LitElement, SVGTemplateResult, html, svg, unsafeCSS} from 'lit';\nimport {customElement, property} from 'lit/decorators.js';\nimport compentStyle from './watch-flat.css?inline';\nimport {Tickmark, TickmarkStyle, tickmark} from './tickmark-flat';\nimport {rect} from '../../svghelpers/rectangular';\nimport {Label} from '../compass-flat/compass-flat';\n\n@customElement('obc-watch-flat')\nexport class ObcWatchFlat extends LitElement {\n @property({type: Number}) width = 352;\n @property({type: Number}) height = 72;\n @property({type: Number}) padding = 0;\n @property({type: Number}) rotation = 0;\n @property({type: Number}) tickmarkSpacing = 0;\n @property({type: Number}) angleSetpoint: number | undefined;\n @property({type: Array, attribute: false}) tickmarks: Tickmark[] = [];\n @property({type: Array, attribute: false}) labels: Label[] = [];\n @property({type: Array, attribute: false}) FOVIndicator: SVGTemplateResult[] =\n [];\n @property({type: Number}) trackHeight = (2 / 3) * this.height;\n @property({type: Number}) ticksHeight = this.height - this.trackHeight;\n @property({type: Number}) borderRadius = 8;\n\n private renderClipPath(offsetY: number = 0): SVGTemplateResult {\n return svg`\n <clipPath id=\"frameClipPath${offsetY === 0 ? '' : 'Tickmarks'}\">\n <rect x=\"${-this.width / 2}\" y=\"${-this.height / 2 + offsetY}\" \n width=\"${this.width}\" height=\"${this.height}\" \n rx=\"${this.borderRadius}\" />\n </clipPath>\n `;\n }\n\n private renderLabelMask(): SVGTemplateResult {\n return svg`\n <mask id=\"labelMask\">\n <rect x=\"${-this.width / 2}\" y=\"${-70}\" \n width=\"${this.width}\" height=\"${32}\"\n />\n <linearGradient id=\"fadeGradient\" gradientUnits=\"userSpaceOnUse\"\n x1=\"${-this.width / 2}\" y1=\"0\" x2=\"${this.width / 2}\" y2=\"0\">\n <stop offset=\"0%\" style=\"stop-color:black; stop-opacity:1;\" />\n <stop offset=\"10%\" style=\"stop-color:white; stop-opacity:1;\" />\n <stop offset=\"50%\" style=\"stop-color:white; stop-opacity:1;\" />\n <stop offset=\"90%\" style=\"stop-color:white; stop-opacity:1;\" />\n <stop offset=\"100%\" style=\"stop-color:black; stop-opacity:1;\" />\n </linearGradient>\n <rect x=\"${-this.width / 2}\" y=\"${-70}\" \n width=\"${this.width}\" height=\"${32}\"\n fill=\"url(#fadeGradient)\" />\n </mask>\n `;\n }\n\n private renderLabels(scale: number): SVGTemplateResult[] {\n const labels: SVGTemplateResult[] = [];\n\n for (const l of this.labels) {\n labels.push(\n svg`<g transform=\"translate(${-this.rotation * this.tickmarkSpacing}, ${-6 / scale})\">\n <text x=${l.x} y=${l.y} class=\"label\" fill=${'var(--instrument-tick-mark-secondary-color)'}>\n ${l.text}\n </text>\n </g>`\n );\n }\n\n return labels;\n }\n\n private watchFace(): SVGTemplateResult {\n const strokeWidth = 1;\n\n return svg`\n ${this.renderClipPath()}\n ${this.renderClipPath(-40)}\n <g clip-path=\"url(#frameClipPath)\">\n ${rect('frame-track', {\n width: this.width,\n height: this.trackHeight,\n y: this.height / 2 - this.trackHeight,\n strokeWidth: strokeWidth,\n strokeColor: 'var(--instrument-frame-secondary-color)',\n strokePosition: 'inside',\n fillColor: 'var(--instrument-frame-secondary-color)',\n borderRadius: 0,\n })}\n ${rect('frame-ticks', {\n width: this.width,\n height: this.ticksHeight,\n y: this.height / 2 - this.trackHeight - this.ticksHeight,\n strokeWidth: strokeWidth,\n strokeColor: 'var(--instrument-frame-primary-color)',\n strokePosition: 'inside',\n fillColor: 'var(--instrument-frame-primary-color)',\n borderRadius: 0,\n })}\n </g>\n ${rect('frame-outline', {\n width: this.width,\n height: this.height,\n strokeWidth: strokeWidth,\n strokeColor: 'var(--instrument-frame-tertiary-color)',\n strokePosition: 'inside',\n fillColor: 'none',\n borderRadius: this.borderRadius,\n })}\n `;\n }\n\n override render() {\n const width = (this.width / 2 + this.padding) * 2;\n const viewBox = `-${width / 2} -${this.height / 2} ${width} ${this.height}`;\n const scale = this.clientWidth / width;\n\n return html`\n <svg\n width=\"100%\"\n height=\"100%\"\n viewBox=${viewBox}\n style=\"--scale: ${scale}\"\n >\n ${this.watchFace()} ${this.renderLabelMask()} ${this.FOVIndicator}\n\n <g clip-path=\"url(#frameClipPath)\">\n ${this.tickmarks.map(\n (t) => svg`\n <g transform=\"translate(${-this.rotation * this.tickmarkSpacing}, 0)\">\n ${tickmark(t.angle, t.type, TickmarkStyle.hinted)}\n </g>\n `\n )}\n </g>\n\n <g mask=\"url(#labelMask)\">\n ${this.renderLabels(scale)}\n </svg>\n `;\n }\n\n static override styles = unsafeCSS(compentStyle);\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'obc-watch-flat': ObcWatchFlat;\n }\n}\n"],"names":[],"mappings":"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"}
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"rectangular.d.ts","sourceRoot":"","sources":["../../src/svghelpers/rectangular.ts"],"names":[],"mappings":"AAEA,wBAAgB,IAAI,CAClB,EAAE,EAAE,MAAM,EACV,IAAI,EAAE;IACJ,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,cAAc,EAAE,QAAQ,GAAG,SAAS,CAAC;
|
1
|
+
{"version":3,"file":"rectangular.d.ts","sourceRoot":"","sources":["../../src/svghelpers/rectangular.ts"],"names":[],"mappings":"AAEA,wBAAgB,IAAI,CAClB,EAAE,EAAE,MAAM,EACV,IAAI,EAAE;IACJ,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,cAAc,EAAE,QAAQ,GAAG,SAAS,CAAC;IACrC,CAAC,CAAC,EAAE,MAAM,CAAC;CACZ,+CA4BF"}
|
@@ -1,13 +1,14 @@
|
|
1
1
|
import { svg } from "lit";
|
2
2
|
function rect(id, data) {
|
3
|
+
const yPosition = data.y !== void 0 ? data.y : -data.height / 2;
|
3
4
|
if (data.strokePosition === "inside") {
|
4
5
|
return svg`
|
5
6
|
<defs>
|
6
7
|
<clipPath id="clip${id}">
|
7
|
-
<rect id=${id} x=${-data.width / 2} y=${
|
8
|
+
<rect id=${id} x=${-data.width / 2} y=${yPosition} width=${data.width} height=${data.height} rx=${data.borderRadius} vector-effect="non-scaling-stroke" />
|
8
9
|
</clipPath>
|
9
10
|
</defs>
|
10
|
-
<rect id=${id} x=${-data.width / 2} y=${
|
11
|
+
<rect id=${id} x=${-data.width / 2} y=${yPosition} width=${data.width} height=${data.height} rx=${data.borderRadius} vector-effect="non-scaling-stroke" stroke=${data.strokeColor} stroke-width=${data.strokeWidth * 2} fill=${data.fillColor} clip-path="url(#clip${id})"/>
|
11
12
|
`;
|
12
13
|
} else {
|
13
14
|
return null;
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"rectangular.js","sources":["../../src/svghelpers/rectangular.ts"],"sourcesContent":["import {svg} from 'lit';\n\nexport function rect(\n id: string,\n data: {\n width: number;\n height: number;\n strokeWidth: number;\n strokeColor: string;\n fillColor: string;\n borderRadius: number;\n strokePosition: 'inside' | 'outside';\n }\n) {\n if (data.strokePosition === 'inside') {\n return svg`\n\t\t<defs>\n\t\t\t<clipPath id=\"clip${id}\">\n\t\t\t\t<rect id=${id} x=${-data.width / 2} y=${
|
1
|
+
{"version":3,"file":"rectangular.js","sources":["../../src/svghelpers/rectangular.ts"],"sourcesContent":["import {svg} from 'lit';\n\nexport function rect(\n id: string,\n data: {\n width: number;\n height: number;\n strokeWidth: number;\n strokeColor: string;\n fillColor: string;\n borderRadius: number;\n strokePosition: 'inside' | 'outside';\n y?: number;\n }\n) {\n const yPosition = data.y !== undefined ? data.y : -data.height / 2;\n\n if (data.strokePosition === 'inside') {\n return svg`\n\t\t<defs>\n\t\t\t<clipPath id=\"clip${id}\">\n\t\t\t\t<rect id=${id} x=${-data.width / 2} y=${yPosition} width=${\n data.width\n } height=${data.height} rx=${\n data.borderRadius\n } vector-effect=\"non-scaling-stroke\" />\n\t\t\t</clipPath>\n\t\t</defs>\n\t\t<rect id=${id} x=${-data.width / 2} y=${yPosition} width=${\n data.width\n } height=${data.height} rx=${\n data.borderRadius\n } vector-effect=\"non-scaling-stroke\" stroke=${\n data.strokeColor\n } stroke-width=${data.strokeWidth * 2} fill=${\n data.fillColor\n } clip-path=\"url(#clip${id})\"/> \n\t\t `;\n } else {\n return null;\n }\n}\n"],"names":[],"mappings":";AAEgB,SAAA,KACd,IACA,MAUA;AACM,QAAA,YAAY,KAAK,MAAM,SAAY,KAAK,IAAI,CAAC,KAAK,SAAS;AAE7D,MAAA,KAAK,mBAAmB,UAAU;AAC7B,WAAA;AAAA;AAAA,uBAEY,EAAE;AAAA,eACV,EAAE,MAAM,CAAC,KAAK,QAAQ,CAAC,MAAM,SAAS,UAC3C,KAAK,KACP,WAAW,KAAK,MAAM,OACpB,KAAK,YACP;AAAA;AAAA;AAAA,aAGK,EAAE,MAAM,CAAC,KAAK,QAAQ,CAAC,MAAM,SAAS,UAC7C,KAAK,KACP,WAAW,KAAK,MAAM,OACpB,KAAK,YACP,8CACE,KAAK,WACP,kBAAkB,KAAK,cAAc,CAAC,SACpC,KAAK,SACP,wBAAwB,EAAE;AAAA;AAAA,EAAA,OAErB;AACE,WAAA;AAAA,EACT;AACF;"}
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@oicl/openbridge-webcomponents",
|
3
|
-
"version": "0.0.15-dev-
|
3
|
+
"version": "0.0.15-dev-20240923190011",
|
4
4
|
"type": "module",
|
5
5
|
"repository": {
|
6
6
|
"type": "git",
|
@@ -35,23 +35,28 @@
|
|
35
35
|
"lit": "^3.1.0"
|
36
36
|
},
|
37
37
|
"devDependencies": {
|
38
|
+
"@chromatic-com/storybook": "^1.7.0",
|
38
39
|
"@custom-elements-manifest/analyzer": "^0.9.0",
|
39
40
|
"@lit-labs/cli": "^0.6.4",
|
40
41
|
"@lit-labs/gen-wrapper-react": "^0.3.2",
|
41
42
|
"@lit-labs/gen-wrapper-vue": "^0.3.3",
|
42
43
|
"@open-wc/lit-helpers": "^0.7.0",
|
43
|
-
"@
|
44
|
-
"@storybook/addon-
|
45
|
-
"@storybook/addon-
|
46
|
-
"@storybook/addon-
|
47
|
-
"@storybook/addon-
|
48
|
-
"@storybook/
|
49
|
-
"@storybook/
|
44
|
+
"@playwright/test": "^1.46.1",
|
45
|
+
"@storybook/addon-essentials": "^8.2.9",
|
46
|
+
"@storybook/addon-interactions": "^8.2.9",
|
47
|
+
"@storybook/addon-links": "^8.2.9",
|
48
|
+
"@storybook/addon-storysource": "^8.2.9",
|
49
|
+
"@storybook/addon-themes": "^8.2.9",
|
50
|
+
"@storybook/blocks": "^8.2.9",
|
51
|
+
"@storybook/manager-api": "^8.2.9",
|
52
|
+
"@storybook/test": "^8.2.9",
|
50
53
|
"@storybook/test-runner": "^0.17.0",
|
51
|
-
"@storybook/
|
52
|
-
"@storybook/web-components
|
54
|
+
"@storybook/theming": "^8.2.9",
|
55
|
+
"@storybook/web-components": "^8.2.9",
|
56
|
+
"@storybook/web-components-vite": "^8.2.9",
|
53
57
|
"@topcli/prompts": "^1.8.0",
|
54
58
|
"@types/jest-image-snapshot": "^6",
|
59
|
+
"@types/node": "^22.4.1",
|
55
60
|
"concurrently": "^8.2.2",
|
56
61
|
"dotenv": "^16.3.1",
|
57
62
|
"eslint": "^8.56.0",
|
@@ -67,7 +72,7 @@
|
|
67
72
|
"prettier": "^3.1.1",
|
68
73
|
"release-it": "^17.1.1",
|
69
74
|
"rollup-plugin-postcss-lit": "^2.1.0",
|
70
|
-
"storybook": "^8.
|
75
|
+
"storybook": "^8.2.9",
|
71
76
|
"tsx": "^4.7.1",
|
72
77
|
"typescript": "^5.3.3",
|
73
78
|
"vite": "^5.2.7",
|
@@ -0,0 +1,61 @@
|
|
1
|
+
import {SVGTemplateResult, svg} from 'lit';
|
2
|
+
|
3
|
+
export enum ArrowStyle {
|
4
|
+
HDG = 'HDG',
|
5
|
+
COG = 'COG',
|
6
|
+
}
|
7
|
+
|
8
|
+
export function arrow(
|
9
|
+
style: ArrowStyle,
|
10
|
+
angle: number
|
11
|
+
): SVGTemplateResult | SVGTemplateResult[] {
|
12
|
+
const colorName = 'var(--instrument-enhanced-secondary-color)';
|
13
|
+
|
14
|
+
if (style === ArrowStyle.HDG) {
|
15
|
+
return svg`
|
16
|
+
<g transform="translate(-32, -${256}) rotate(${angle}, 32, 256)">
|
17
|
+
<rect x="28" y="118" width="8" height="139" rx="4" fill="${colorName}" />
|
18
|
+
<rect x="30.0039" y="256" width="4" height="156" rx="2" fill="${colorName}" />
|
19
|
+
<circle cx="32" cy="256" r="8" fill="${colorName}" />
|
20
|
+
<mask
|
21
|
+
id="mask0_262_65165"
|
22
|
+
style="mask-type:luminance"
|
23
|
+
maskUnits="userSpaceOnUse"
|
24
|
+
x="8"
|
25
|
+
y="94"
|
26
|
+
width="48"
|
27
|
+
height="50"
|
28
|
+
>
|
29
|
+
<path
|
30
|
+
d="M13.2833 140.564L32 96L50.7167 140.564C51.4569 142.326 49.54 144.023 47.8805 143.075L32 136L16.1195 143.075C14.46 144.023 12.5432 142.326 13.2833 140.564Z"
|
31
|
+
fill="white"
|
32
|
+
stroke="black"
|
33
|
+
/>
|
34
|
+
</mask>
|
35
|
+
<g mask="url(#mask0_262_65165)">
|
36
|
+
<path
|
37
|
+
d="M13.2833 140.564L32 96L50.7167 140.564C51.4569 142.326 49.54 144.023 47.8805 143.075L32 136L16.1195 143.075C14.46 144.023 12.5432 142.326 13.2833 140.564Z"
|
38
|
+
fill="${colorName}"
|
39
|
+
/>
|
40
|
+
</g>
|
41
|
+
</g>
|
42
|
+
`;
|
43
|
+
} else if (style === ArrowStyle.COG) {
|
44
|
+
return svg`
|
45
|
+
<g transform="translate(-32, -${256}) rotate(${angle}, 32, 256)">
|
46
|
+
<path
|
47
|
+
fill-rule="evenodd"
|
48
|
+
clip-rule="evenodd"
|
49
|
+
d="M13.2833 140.564C12.5431 142.326 14.46 144.023 16.1195 143.075L32 136L47.8805 143.075C49.54 144.023 51.4568 142.326 50.7167 140.564L32 96L13.2833 140.564ZM32 106.33L19.2545 136.676L32 131.393L44.7455 136.676L32 106.33ZM49.865 139.602L49.8625 139.6L49.865 139.602Z"
|
50
|
+
fill="${colorName}"
|
51
|
+
/>
|
52
|
+
<rect x="30" y="133" width="4" height="124" rx="2" fill="${colorName}" />
|
53
|
+
<circle cx="32" cy="256" r="4" fill="${colorName}" />
|
54
|
+
</g>
|
55
|
+
`;
|
56
|
+
} else {
|
57
|
+
return [];
|
58
|
+
}
|
59
|
+
|
60
|
+
// return [...shaft, circle, arrowTip];
|
61
|
+
}
|
@@ -0,0 +1,37 @@
|
|
1
|
+
import type {Meta, StoryObj} from '@storybook/web-components';
|
2
|
+
import {ObcCompass} from './compass';
|
3
|
+
import './compass';
|
4
|
+
import {beta6Decorator, widthDecorator} from '../../storybook-util';
|
5
|
+
import {AdviceType} from '../watch/advice';
|
6
|
+
|
7
|
+
const meta: Meta<typeof ObcCompass> = {
|
8
|
+
title: 'Navigation Instruments/Compass',
|
9
|
+
tags: ['autodocs'],
|
10
|
+
component: 'obc-compass',
|
11
|
+
args: {
|
12
|
+
width: 512,
|
13
|
+
heading: 311,
|
14
|
+
courseOverGround: 338,
|
15
|
+
headingAdvices: [
|
16
|
+
{
|
17
|
+
minAngle: 20,
|
18
|
+
maxAngle: 50,
|
19
|
+
type: AdviceType.advice,
|
20
|
+
hinted: false,
|
21
|
+
},
|
22
|
+
],
|
23
|
+
},
|
24
|
+
argTypes: {
|
25
|
+
width: {control: {type: 'range', min: 32, max: 1028, step: 1}},
|
26
|
+
heading: {control: {type: 'range', min: 0, max: 360, step: 1}},
|
27
|
+
courseOverGround: {control: {type: 'range', min: 0, max: 360, step: 1}},
|
28
|
+
},
|
29
|
+
decorators: [widthDecorator, beta6Decorator],
|
30
|
+
} satisfies Meta<ObcCompass>;
|
31
|
+
|
32
|
+
export default meta;
|
33
|
+
type Story = StoryObj<ObcCompass>;
|
34
|
+
|
35
|
+
export const Primary: Story = {
|
36
|
+
args: {},
|
37
|
+
};
|
@@ -0,0 +1,132 @@
|
|
1
|
+
import {LitElement, css, html} from 'lit';
|
2
|
+
import {customElement, property} from 'lit/decorators.js';
|
3
|
+
import '../watch/watch';
|
4
|
+
import {Tickmark, TickmarkType} from '../watch/tickmark';
|
5
|
+
import {arrow, ArrowStyle} from './arrow';
|
6
|
+
import {
|
7
|
+
AdviceState,
|
8
|
+
AdviceType,
|
9
|
+
AngleAdvice,
|
10
|
+
AngleAdviceRaw,
|
11
|
+
} from '../watch/advice';
|
12
|
+
import {radialTickmarks} from './radial-tickmark';
|
13
|
+
|
14
|
+
@customElement('obc-compass')
|
15
|
+
export class ObcCompass extends LitElement {
|
16
|
+
@property({type: Number}) heading = 0;
|
17
|
+
@property({type: Number}) courseOverGround = 0;
|
18
|
+
@property({type: Number}) padding = 48;
|
19
|
+
@property({type: Array, attribute: false}) headingAdvices: AngleAdvice[] = [];
|
20
|
+
@property({type: Number}) containerWidth = 0;
|
21
|
+
|
22
|
+
private resizeObserver: ResizeObserver = new ResizeObserver((entries) => {
|
23
|
+
for (const entry of entries) {
|
24
|
+
this.containerWidth = entry.contentRect.width;
|
25
|
+
this.adjustPadding();
|
26
|
+
}
|
27
|
+
});
|
28
|
+
|
29
|
+
override connectedCallback() {
|
30
|
+
super.connectedCallback();
|
31
|
+
this.resizeObserver.observe(this);
|
32
|
+
}
|
33
|
+
|
34
|
+
override disconnectedCallback() {
|
35
|
+
super.disconnectedCallback();
|
36
|
+
this.resizeObserver.unobserve(this);
|
37
|
+
}
|
38
|
+
|
39
|
+
private adjustPadding() {
|
40
|
+
const deltaWidth = 512 - this.containerWidth;
|
41
|
+
const steps = deltaWidth / 128;
|
42
|
+
let deltaPadding = 0;
|
43
|
+
if (deltaWidth > 0) {
|
44
|
+
deltaPadding = steps * 48;
|
45
|
+
} else {
|
46
|
+
deltaPadding = steps * 6;
|
47
|
+
}
|
48
|
+
|
49
|
+
this.padding = 72 + deltaPadding;
|
50
|
+
}
|
51
|
+
|
52
|
+
private get angleAdviceRaw(): AngleAdviceRaw[] {
|
53
|
+
return this.headingAdvices.map(({minAngle, maxAngle, hinted, type}) => {
|
54
|
+
const state =
|
55
|
+
this.heading >= minAngle && this.heading <= maxAngle
|
56
|
+
? AdviceState.triggered
|
57
|
+
: hinted
|
58
|
+
? AdviceState.hinted
|
59
|
+
: AdviceState.regular;
|
60
|
+
return {minAngle, maxAngle, type, state};
|
61
|
+
});
|
62
|
+
}
|
63
|
+
|
64
|
+
override render() {
|
65
|
+
const tickmarks: Tickmark[] = [
|
66
|
+
{angle: 0, type: TickmarkType.main},
|
67
|
+
{angle: 90, type: TickmarkType.main},
|
68
|
+
{angle: 180, type: TickmarkType.main},
|
69
|
+
{angle: 270, type: TickmarkType.main},
|
70
|
+
];
|
71
|
+
|
72
|
+
const rt = this.headingAdvices.map(({minAngle, maxAngle, type}) =>
|
73
|
+
radialTickmarks(
|
74
|
+
minAngle,
|
75
|
+
maxAngle,
|
76
|
+
type === AdviceType.caution ? TickmarkType.secondary : undefined
|
77
|
+
)
|
78
|
+
);
|
79
|
+
|
80
|
+
const width = (176 + this.padding) * 2;
|
81
|
+
const viewBox = `-${width / 2} -${width / 2} ${width} ${width}`;
|
82
|
+
|
83
|
+
return html`
|
84
|
+
<div class="container">
|
85
|
+
<obc-watch
|
86
|
+
.padding=${this.padding}
|
87
|
+
.advices=${this.angleAdviceRaw}
|
88
|
+
.tickmarks=${tickmarks}
|
89
|
+
.labelFrameEnabled=${true}
|
90
|
+
.crosshairEnabled=${true}
|
91
|
+
>
|
92
|
+
</obc-watch>
|
93
|
+
<svg viewBox="${viewBox}">
|
94
|
+
${rt} ${arrow(ArrowStyle.HDG, this.heading)}
|
95
|
+
${arrow(ArrowStyle.COG, this.courseOverGround)}
|
96
|
+
</svg>
|
97
|
+
</div>
|
98
|
+
`;
|
99
|
+
}
|
100
|
+
|
101
|
+
static override styles = css`
|
102
|
+
* {
|
103
|
+
box-sizing: border-box;
|
104
|
+
}
|
105
|
+
|
106
|
+
.container {
|
107
|
+
position: relative;
|
108
|
+
width: 100%;
|
109
|
+
height: 100%;
|
110
|
+
}
|
111
|
+
|
112
|
+
.container > * {
|
113
|
+
position: absolute;
|
114
|
+
top: 0;
|
115
|
+
left: 0;
|
116
|
+
width: 100%;
|
117
|
+
height: 100%;
|
118
|
+
}
|
119
|
+
|
120
|
+
:host {
|
121
|
+
display: block;
|
122
|
+
width: 100%;
|
123
|
+
height: 100%;
|
124
|
+
}
|
125
|
+
`;
|
126
|
+
}
|
127
|
+
|
128
|
+
declare global {
|
129
|
+
interface HTMLElementTagNameMap {
|
130
|
+
'obc-compass': ObcCompass;
|
131
|
+
}
|
132
|
+
}
|
@@ -0,0 +1,77 @@
|
|
1
|
+
import {SVGTemplateResult, svg} from 'lit';
|
2
|
+
import {TickmarkType, TickmarkStyle, tickmarkColor} from '../watch/tickmark';
|
3
|
+
|
4
|
+
export function radialTickmarks(
|
5
|
+
minAngle: number,
|
6
|
+
maxAngle: number,
|
7
|
+
type: TickmarkType | undefined
|
8
|
+
): SVGTemplateResult[] {
|
9
|
+
if (type === TickmarkType.main || type === TickmarkType.tertiary) {
|
10
|
+
throw new Error(
|
11
|
+
'Only secondary tickmarks or undefined tickmarks (dots) are supported'
|
12
|
+
);
|
13
|
+
}
|
14
|
+
|
15
|
+
const origin = {x: 0, y: 0};
|
16
|
+
const radius = 320 / 2;
|
17
|
+
const strokeWidth = '1.2';
|
18
|
+
const margin = 1.5;
|
19
|
+
const colorName = tickmarkColor(TickmarkStyle.hinted);
|
20
|
+
const tickWidth = type === TickmarkType.secondary ? 4 : 1;
|
21
|
+
const tickmarks: SVGTemplateResult[] = [];
|
22
|
+
|
23
|
+
const sinMin = Math.sin((minAngle * Math.PI) / 180);
|
24
|
+
const cosMin = Math.cos((minAngle * Math.PI) / 180);
|
25
|
+
const sinMax = Math.sin((maxAngle * Math.PI) / 180);
|
26
|
+
const cosMax = Math.cos((maxAngle * Math.PI) / 180);
|
27
|
+
|
28
|
+
const deltaIncrement = tickWidth * margin;
|
29
|
+
|
30
|
+
for (let deltaR = 0; deltaR <= radius; deltaR += deltaIncrement) {
|
31
|
+
const xMin = origin.x + sinMin * deltaR;
|
32
|
+
const yMin = origin.y - cosMin * deltaR;
|
33
|
+
const xMax = origin.x + sinMax * deltaR;
|
34
|
+
const yMax = origin.y - cosMax * deltaR;
|
35
|
+
|
36
|
+
if (type === undefined) {
|
37
|
+
const size = 1;
|
38
|
+
tickmarks.push(
|
39
|
+
svg`<rect
|
40
|
+
x=${xMin - size / 2}
|
41
|
+
y=${yMin - size / 2}
|
42
|
+
width=${size}
|
43
|
+
height=${size}
|
44
|
+
fill=${colorName}
|
45
|
+
transform="rotate(${minAngle} ${xMin} ${yMin})"
|
46
|
+
vector-effect="non-scaling-stroke"/>`
|
47
|
+
);
|
48
|
+
tickmarks.push(
|
49
|
+
svg`<rect
|
50
|
+
x=${xMax - size / 2}
|
51
|
+
y=${yMax - size / 2}
|
52
|
+
width=${size}
|
53
|
+
height=${size}
|
54
|
+
fill=${colorName}
|
55
|
+
transform="rotate(${maxAngle} ${xMax} ${yMax})"
|
56
|
+
vector-effect="non-scaling-stroke"/>`
|
57
|
+
);
|
58
|
+
} else {
|
59
|
+
const currentRadius = Math.min(deltaR + tickWidth, radius);
|
60
|
+
const x2Min = origin.x + sinMin * currentRadius;
|
61
|
+
const y2Min = origin.y - cosMin * currentRadius;
|
62
|
+
const x2Max = origin.x + sinMax * currentRadius;
|
63
|
+
const y2Max = origin.y - cosMax * currentRadius;
|
64
|
+
|
65
|
+
tickmarks.push(
|
66
|
+
svg`<line x1=${xMin} y1=${yMin} x2=${x2Min} y2=${y2Min} stroke=${colorName} stroke-width=${strokeWidth} vector-effect="non-scaling-stroke"/>`
|
67
|
+
);
|
68
|
+
tickmarks.push(
|
69
|
+
svg`<line x1=${xMax} y1=${yMax} x2=${x2Max} y2=${y2Max} stroke=${colorName} stroke-width=${strokeWidth} vector-effect="non-scaling-stroke"/>`
|
70
|
+
);
|
71
|
+
|
72
|
+
if (currentRadius >= radius) break;
|
73
|
+
}
|
74
|
+
}
|
75
|
+
|
76
|
+
return tickmarks;
|
77
|
+
}
|
@@ -0,0 +1,23 @@
|
|
1
|
+
* {
|
2
|
+
box-sizing: border-box;
|
3
|
+
}
|
4
|
+
|
5
|
+
.container {
|
6
|
+
position: relative;
|
7
|
+
width: 100%;
|
8
|
+
height: 100%;
|
9
|
+
}
|
10
|
+
|
11
|
+
.container > * {
|
12
|
+
position: absolute;
|
13
|
+
top: 0;
|
14
|
+
left: 0;
|
15
|
+
width: 100%;
|
16
|
+
height: 100%;
|
17
|
+
}
|
18
|
+
|
19
|
+
:host {
|
20
|
+
display: block;
|
21
|
+
width: 100%;
|
22
|
+
height: 100%;
|
23
|
+
}
|
@@ -0,0 +1,35 @@
|
|
1
|
+
import type {Meta, StoryObj} from '@storybook/web-components';
|
2
|
+
import {ObcCompassFlat} from './compass-flat';
|
3
|
+
import './compass-flat';
|
4
|
+
import {beta6Decorator, widthDecorator} from '../../storybook-util';
|
5
|
+
import {LabelPosition} from './compass-flat';
|
6
|
+
|
7
|
+
const meta: Meta<typeof ObcCompassFlat> = {
|
8
|
+
title: 'Navigation Instruments/Compass flat',
|
9
|
+
tags: ['autodocs'],
|
10
|
+
component: 'obc-compass-flat',
|
11
|
+
args: {
|
12
|
+
width: 512,
|
13
|
+
heading: 45,
|
14
|
+
courseOverGround: 50,
|
15
|
+
FOVIndicator: false,
|
16
|
+
minFOV: 90,
|
17
|
+
},
|
18
|
+
argTypes: {
|
19
|
+
width: {control: {type: 'range', min: 32, max: 1028, step: 1}},
|
20
|
+
heading: {control: {type: 'range', min: 0, max: 360, step: 1}},
|
21
|
+
courseOverGround: {control: {type: 'range', min: 0, max: 360, step: 1}},
|
22
|
+
},
|
23
|
+
decorators: [widthDecorator, beta6Decorator],
|
24
|
+
} satisfies Meta<ObcCompassFlat>;
|
25
|
+
|
26
|
+
export default meta;
|
27
|
+
type Story = StoryObj<ObcCompassFlat>;
|
28
|
+
|
29
|
+
export const Primary: Story = {};
|
30
|
+
|
31
|
+
export const WithFOVIndicator: Story = {
|
32
|
+
args: {
|
33
|
+
FOVIndicator: true,
|
34
|
+
},
|
35
|
+
};
|