@oicl/openbridge-webcomponents-full-bundle 2.0.0-next.67 → 2.0.0-next.69
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 +18339 -18091
- package/bundle/openbridge-webcomponents.bundle.js.map +1 -1
- package/custom-elements.json +209 -0
- package/dist/integration-systems/integration-vessel-menu/integration-vessel-menu.css.js +7 -4
- package/dist/integration-systems/integration-vessel-menu/integration-vessel-menu.css.js.map +1 -1
- package/dist/navigation-instruments/graph-mini/graph-mini.css.js +2 -1
- package/dist/navigation-instruments/graph-mini/graph-mini.css.js.map +1 -1
- package/dist/navigation-instruments/graph-mini/graph-mini.d.ts.map +1 -1
- package/dist/navigation-instruments/graph-mini/graph-mini.js +7 -5
- package/dist/navigation-instruments/graph-mini/graph-mini.js.map +1 -1
- package/dist/navigation-instruments/indicator-graph/indicator-graph.css.js +66 -0
- package/dist/navigation-instruments/indicator-graph/indicator-graph.css.js.map +1 -0
- package/dist/navigation-instruments/indicator-graph/indicator-graph.d.ts +54 -0
- package/dist/navigation-instruments/indicator-graph/indicator-graph.d.ts.map +1 -0
- package/dist/navigation-instruments/indicator-graph/indicator-graph.js +203 -0
- package/dist/navigation-instruments/indicator-graph/indicator-graph.js.map +1 -0
- package/package.json +1 -1
- package/src/integration-systems/integration-vessel-menu/integration-vessel-menu.css +7 -4
- package/src/integration-systems/integration-vessel-menu/integration-vessel-menu.stories.ts +23 -0
- package/src/navigation-instruments/graph-mini/graph-mini.css +2 -1
- package/src/navigation-instruments/graph-mini/graph-mini.stories.ts +11 -3
- package/src/navigation-instruments/graph-mini/graph-mini.ts +7 -5
- package/src/navigation-instruments/indicator-graph/indicator-graph.css +55 -0
- package/src/navigation-instruments/indicator-graph/indicator-graph.stories.ts +116 -0
- package/src/navigation-instruments/indicator-graph/indicator-graph.ts +222 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"indicator-graph.js","sources":["../../../src/navigation-instruments/indicator-graph/indicator-graph.ts"],"sourcesContent":["import {LitElement, PropertyValues, html, unsafeCSS} from 'lit';\nimport {property, query, state} from 'lit/decorators.js';\nimport compentStyle from './indicator-graph.css?inline';\nimport uPlot from 'uplot';\nimport {customElement} from '../../decorator.js';\n\nexport enum ObcIndicatorGraphSize {\n small = 'small',\n medium = 'medium',\n large = 'large',\n}\n\nexport enum ObcIndicatorGraphPriority {\n regular = 'regular',\n enhanced = 'enhanced',\n}\n\nexport interface ObcIndicatorGraphLayout {\n size?: ObcIndicatorGraphSize;\n priority?: ObcIndicatorGraphPriority;\n y?: {min?: number; max?: number};\n}\n\n/**\n * @element obc-indicator-graph\n * @description A mini graph component\n *\n * @property {Array} data - The data to display in the graph, first array is the x values, second array is the y values\n */\n@customElement('obc-indicator-graph')\nexport class ObcIndicatorGraph extends LitElement {\n @property({type: Array})\n data: [number[], number[]] = [[], []];\n\n @property({type: Object})\n layout: ObcIndicatorGraphLayout = {};\n\n @query('.chart-container')\n private chart!: HTMLDivElement;\n\n @state()\n private y: number = 24;\n\n @state()\n private zeroLineY: number = 0;\n\n private uplot: uPlot | null = null;\n private resizeObserver: ResizeObserver | null = null;\n\n private getCssColor(name: string) {\n const color = getComputedStyle(this).getPropertyValue(name).trim();\n return color;\n }\n\n override firstUpdated() {\n const opts = {\n width: this.chart.clientWidth,\n height: this.chart.clientHeight,\n scales: {\n x: {time: false, show: false},\n y: {\n auto: true,\n show: false,\n range: this._range.bind(this),\n },\n },\n series: [\n {},\n {\n stroke: this._getStrokeColor(),\n width: this._getStrokeWidth(),\n points: {show: false},\n },\n ],\n axes: [\n {show: false},\n {ticks: {show: false}, show: false, grid: {show: false}},\n ],\n legend: {show: false},\n cursor: {show: false},\n };\n\n this.uplot = new uPlot(opts, this.data, this.chart);\n requestAnimationFrame(() => this.updateY());\n\n this.resizeObserver = new ResizeObserver(() => this.updateSize());\n this.resizeObserver.observe(this.chart);\n }\n\n override disconnectedCallback() {\n super.disconnectedCallback();\n this.resizeObserver?.disconnect();\n this.resizeObserver = null;\n this.uplot?.destroy();\n this.uplot = null;\n }\n\n private updateSize() {\n if (!this.uplot) {\n return;\n }\n this.uplot.setSize({\n width: this.chart.clientWidth,\n height: this.chart.clientHeight,\n });\n this.updateY();\n }\n\n private _range(\n _self: uPlot,\n initMin: number,\n initMax: number,\n _scaleKey: string\n ): [number, number] {\n const {min: minY, max: maxY} = this.layout.y ?? {};\n const range = maxY ?? initMax - (minY ?? initMin);\n let min = minY ?? initMin - range * 0.1;\n if (minY === undefined) {\n min = Math.min(0, min);\n }\n return [min, maxY ?? initMax + range * 0.1] as [number, number];\n }\n\n private get _effectiveSize() {\n return this.layout.size ?? ObcIndicatorGraphSize.medium;\n }\n\n private get _effectivePriority() {\n return this.layout.priority ?? ObcIndicatorGraphPriority.regular;\n }\n\n private _getStrokeWidth() {\n switch (this._effectiveSize) {\n case ObcIndicatorGraphSize.small:\n return 1;\n case ObcIndicatorGraphSize.medium:\n return 1.5;\n case ObcIndicatorGraphSize.large:\n return 2;\n }\n }\n\n private _getStrokeColor() {\n switch (this._effectivePriority) {\n case ObcIndicatorGraphPriority.regular:\n return this.getCssColor('--element-neutral-color');\n case ObcIndicatorGraphPriority.enhanced:\n return this.getCssColor('--element-neutral-enhanced-color');\n }\n }\n\n updatePalette() {\n if (!this.uplot) {\n return;\n }\n const stroke = this._getStrokeColor();\n this.uplot.setSeries(1, {\n // @ts-expect-error - stroke is not a property of the Series interface\n stroke: stroke,\n width: this._getStrokeWidth(),\n points: {show: false},\n });\n }\n\n private updateY() {\n if (!this.uplot) {\n return;\n }\n const lastY = this.data[1][this.data[1].length - 1];\n // @ts-expect-error - valToPct is not a property of the Scale interface\n const yRatio = this.uplot.scales.y.valToPct(lastY);\n this.y = yRatio * this.chart.clientHeight;\n this.updateZeroLine();\n }\n\n private updateZeroLine() {\n if (!this.uplot) {\n return;\n }\n // @ts-expect-error - valToPct is not a property of the Scale interface\n const yRatio = this.uplot.scales.y.valToPct(0);\n this.zeroLineY = yRatio * this.chart.clientHeight;\n }\n\n override updated(changedProperties: PropertyValues) {\n if (changedProperties.has('data') || changedProperties.has('layout')) {\n this.updatePalette();\n this.uplot?.setData(this.data);\n requestAnimationFrame(() => this.updateY());\n }\n }\n\n override render() {\n return html`\n <div\n class=\"chart-container ${this._effectivePriority} ${this\n ._effectiveSize}\"\n >\n <div\n id=\"zero-line\"\n style=\"transform: translateY(${-this.zeroLineY}px);\n display: ${this.zeroLineY > -0.5 ? 'block' : 'none'};\n \"\n ></div>\n <div\n id=\"dot\"\n style=\"transform: translateY(${-this.y}px);\n display: ${this.y > -0.5 ? 'block' : 'none'};\n \"\n ></div>\n </div>\n `;\n }\n\n static override styles = unsafeCSS(compentStyle);\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'obc-indicator-graph': ObcIndicatorGraph;\n }\n}\n"],"names":["ObcIndicatorGraphSize","ObcIndicatorGraphPriority"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -42,10 +42,6 @@
|
|
|
42
42
|
border-radius: 8px;
|
|
43
43
|
}
|
|
44
44
|
|
|
45
|
-
.footer-container slot[name="buttons"]::slotted(:not(obc-button)) {
|
|
46
|
-
display: contents;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
45
|
.footer-container slot[name="buttons"]::slotted(*) {
|
|
50
46
|
display: flex;
|
|
51
47
|
flex: 1 1 0px;
|
|
@@ -53,6 +49,13 @@
|
|
|
53
49
|
white-space: nowrap;
|
|
54
50
|
}
|
|
55
51
|
|
|
52
|
+
.footer-container slot[name="buttons"]::slotted(:not(obc-button)) {
|
|
53
|
+
display: grid;
|
|
54
|
+
grid-auto-flow: column;
|
|
55
|
+
grid-auto-columns: minmax(auto, 1fr);
|
|
56
|
+
gap: var(--app-components-integration-system-menu-action-spacing);
|
|
57
|
+
}
|
|
58
|
+
|
|
56
59
|
.buttons-slot {
|
|
57
60
|
display: contents;
|
|
58
61
|
}
|
|
@@ -195,6 +195,25 @@ const templateWithoutAlarms: IntegrationVesselMenuTemplate = (args) => html`
|
|
|
195
195
|
</obc-integration-vessel-menu>
|
|
196
196
|
`;
|
|
197
197
|
|
|
198
|
+
const templateWrappedButtons: IntegrationVesselMenuTemplate = (args) => html`
|
|
199
|
+
<obc-integration-vessel-menu .hideAlarmList=${args.hideAlarmList}>
|
|
200
|
+
<div slot="buttons">
|
|
201
|
+
<div style="display: contents;">
|
|
202
|
+
<obc-button ?fullWidth=${true}>Open</obc-button>
|
|
203
|
+
</div>
|
|
204
|
+
<div style="display: contents;">
|
|
205
|
+
<obc-button ?fullWidth=${true}>Alerts</obc-button>
|
|
206
|
+
</div>
|
|
207
|
+
</div>
|
|
208
|
+
<div slot="content" style="padding: 24px;">
|
|
209
|
+
<div style="width: 320px;">
|
|
210
|
+
<p>Content area</p>
|
|
211
|
+
</div>
|
|
212
|
+
</div>
|
|
213
|
+
${renderAlarms()}
|
|
214
|
+
</obc-integration-vessel-menu>
|
|
215
|
+
`;
|
|
216
|
+
|
|
198
217
|
export const Default: Story = {
|
|
199
218
|
render: template,
|
|
200
219
|
};
|
|
@@ -207,3 +226,7 @@ export const WithoutAlarmsHideEmptyAlarmList: Story = {
|
|
|
207
226
|
render: templateWithoutAlarms,
|
|
208
227
|
args: {hideAlarmList: true},
|
|
209
228
|
};
|
|
229
|
+
|
|
230
|
+
export const WithButtonsWrappedInDivWithoutStyling: Story = {
|
|
231
|
+
render: templateWrappedButtons,
|
|
232
|
+
};
|
|
@@ -19,13 +19,22 @@ type Story = StoryObj<ObcGraphMini>;
|
|
|
19
19
|
|
|
20
20
|
export const Primary: Story = {};
|
|
21
21
|
|
|
22
|
+
export const WithRange: Story = {
|
|
23
|
+
args: {
|
|
24
|
+
minY: -10,
|
|
25
|
+
maxY: 10,
|
|
26
|
+
},
|
|
27
|
+
};
|
|
28
|
+
|
|
22
29
|
export const Realtime: Story = {
|
|
23
30
|
tags: ['skip-test'],
|
|
24
31
|
args: {
|
|
25
32
|
data: [
|
|
26
33
|
Array.from({length: 60}, (_, i) => i),
|
|
27
|
-
Array.from({length: 60}, (_, i) => Math.sin((i / 60) * 2 * Math.PI)),
|
|
34
|
+
Array.from({length: 60}, (_, i) => Math.sin((i / 60 / 5) * 2 * Math.PI)),
|
|
28
35
|
],
|
|
36
|
+
minY: -1.1,
|
|
37
|
+
maxY: 1.1,
|
|
29
38
|
},
|
|
30
39
|
play: async ({canvasElement}) => {
|
|
31
40
|
const graph = canvasElement.querySelector('obc-graph-mini') as ObcGraphMini;
|
|
@@ -35,10 +44,9 @@ export const Realtime: Story = {
|
|
|
35
44
|
|
|
36
45
|
let i = graph.data[0].length;
|
|
37
46
|
setInterval(() => {
|
|
38
|
-
console.log('updating', i);
|
|
39
47
|
const data = graph.data;
|
|
40
48
|
const x = [...data[0], i];
|
|
41
|
-
const y = [...data[1], Math.sin((i / 60) * 2 * Math.PI)];
|
|
49
|
+
const y = [...data[1], Math.sin((i / 60 / 5) * 2 * Math.PI)];
|
|
42
50
|
x.shift();
|
|
43
51
|
y.shift();
|
|
44
52
|
const newData: [number[], number[]] = [x, y];
|
|
@@ -36,8 +36,8 @@ export class ObcGraphMini extends LitElement {
|
|
|
36
36
|
|
|
37
37
|
override firstUpdated() {
|
|
38
38
|
const opts = {
|
|
39
|
-
width:
|
|
40
|
-
height:
|
|
39
|
+
width: 32,
|
|
40
|
+
height: 32,
|
|
41
41
|
scales: {
|
|
42
42
|
x: {time: false, show: false},
|
|
43
43
|
y: {
|
|
@@ -61,7 +61,7 @@ export class ObcGraphMini extends LitElement {
|
|
|
61
61
|
{},
|
|
62
62
|
{
|
|
63
63
|
stroke: this.getCssColor('--element-neutral-color'),
|
|
64
|
-
width:
|
|
64
|
+
width: 1,
|
|
65
65
|
points: {show: false},
|
|
66
66
|
},
|
|
67
67
|
],
|
|
@@ -83,7 +83,7 @@ export class ObcGraphMini extends LitElement {
|
|
|
83
83
|
}
|
|
84
84
|
const stroke = this.getCssColor('--element-neutral-color');
|
|
85
85
|
// @ts-expect-error - stroke is not a property of the Series interface
|
|
86
|
-
this.uplot.setSeries(1, {stroke: stroke, width:
|
|
86
|
+
this.uplot.setSeries(1, {stroke: stroke, width: 1, points: {show: false}});
|
|
87
87
|
}
|
|
88
88
|
|
|
89
89
|
private updateY() {
|
|
@@ -107,7 +107,9 @@ export class ObcGraphMini extends LitElement {
|
|
|
107
107
|
override render() {
|
|
108
108
|
return html`
|
|
109
109
|
<div class="chart-container">
|
|
110
|
-
<div id="chart"
|
|
110
|
+
<div id="chart">
|
|
111
|
+
<div id="dot" style="transform: translateY(${-this.y}px);"></div>
|
|
112
|
+
</div>
|
|
111
113
|
</div>
|
|
112
114
|
`;
|
|
113
115
|
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
.chart-container {
|
|
2
|
+
width: 100%;
|
|
3
|
+
height: 100%;
|
|
4
|
+
display: flex;
|
|
5
|
+
align-items: center;
|
|
6
|
+
justify-content: center;
|
|
7
|
+
position: relative;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
canvas {
|
|
11
|
+
position: absolute;
|
|
12
|
+
width: 100%;
|
|
13
|
+
height: 100%;
|
|
14
|
+
top: 0;
|
|
15
|
+
left: 0;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
#dot {
|
|
19
|
+
position: absolute;
|
|
20
|
+
width: 4px;
|
|
21
|
+
height: 4px;
|
|
22
|
+
right: -3px;
|
|
23
|
+
bottom: -3px;
|
|
24
|
+
border-radius: 50%;
|
|
25
|
+
background: var(--element-neutral-color);
|
|
26
|
+
border: 1px solid var(--border-silhouette-color);
|
|
27
|
+
z-index: 1;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
.enhanced #dot {
|
|
31
|
+
background: var(--element-neutral-enhanced-color);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
.medium #dot {
|
|
35
|
+
width: 6px;
|
|
36
|
+
height: 6px;
|
|
37
|
+
right: -4px;
|
|
38
|
+
bottom: -4px;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
.large #dot {
|
|
42
|
+
width: 8px;
|
|
43
|
+
height: 8px;
|
|
44
|
+
right: -5px;
|
|
45
|
+
bottom: -5px;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
#zero-line {
|
|
49
|
+
position: absolute;
|
|
50
|
+
width: 100%;
|
|
51
|
+
height: 1px;
|
|
52
|
+
bottom: -0.5px;
|
|
53
|
+
background: var(--element-disabled-color);
|
|
54
|
+
border-radius: 2px;
|
|
55
|
+
}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import type {Meta, StoryObj} from '@storybook/web-components-vite';
|
|
2
|
+
import {
|
|
3
|
+
ObcIndicatorGraph,
|
|
4
|
+
ObcIndicatorGraphPriority,
|
|
5
|
+
ObcIndicatorGraphSize,
|
|
6
|
+
} from './indicator-graph.js';
|
|
7
|
+
import './indicator-graph.js';
|
|
8
|
+
import {widthDecorator} from '../../storybook-util.js';
|
|
9
|
+
const meta: Meta<typeof ObcIndicatorGraph> = {
|
|
10
|
+
title: 'Bars and Graphs/Indicator Graph',
|
|
11
|
+
tags: ['6.0', 'autodocs'],
|
|
12
|
+
component: 'obc-indicator-graph',
|
|
13
|
+
decorators: [widthDecorator],
|
|
14
|
+
args: {
|
|
15
|
+
data: [
|
|
16
|
+
Array.from({length: 30}, (_, i) => i),
|
|
17
|
+
Array.from({length: 30}, (_, i) => 2 + Math.sin((i / 30) * 2 * Math.PI)),
|
|
18
|
+
],
|
|
19
|
+
width: 400,
|
|
20
|
+
height: 400,
|
|
21
|
+
},
|
|
22
|
+
argTypes: {
|
|
23
|
+
width: {control: {type: 'range', min: 100, max: 1000, step: 1}},
|
|
24
|
+
height: {control: {type: 'range', min: 100, max: 1000, step: 1}},
|
|
25
|
+
},
|
|
26
|
+
} satisfies Meta<ObcIndicatorGraph>;
|
|
27
|
+
|
|
28
|
+
export default meta;
|
|
29
|
+
type Story = StoryObj<ObcIndicatorGraph>;
|
|
30
|
+
|
|
31
|
+
export const Primary: Story = {};
|
|
32
|
+
|
|
33
|
+
export const WithRange: Story = {
|
|
34
|
+
args: {
|
|
35
|
+
layout: {
|
|
36
|
+
size: ObcIndicatorGraphSize.medium,
|
|
37
|
+
priority: ObcIndicatorGraphPriority.regular,
|
|
38
|
+
y: {min: -10, max: 10},
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
export const Enhanced: Story = {
|
|
44
|
+
args: {
|
|
45
|
+
layout: {
|
|
46
|
+
size: ObcIndicatorGraphSize.medium,
|
|
47
|
+
priority: ObcIndicatorGraphPriority.enhanced,
|
|
48
|
+
},
|
|
49
|
+
},
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
export const Small: Story = {
|
|
53
|
+
args: {
|
|
54
|
+
layout: {
|
|
55
|
+
size: ObcIndicatorGraphSize.small,
|
|
56
|
+
},
|
|
57
|
+
},
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
export const Medium: Story = {
|
|
61
|
+
args: {
|
|
62
|
+
layout: {
|
|
63
|
+
size: ObcIndicatorGraphSize.medium,
|
|
64
|
+
},
|
|
65
|
+
},
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
export const Large: Story = {
|
|
69
|
+
args: {
|
|
70
|
+
layout: {
|
|
71
|
+
size: ObcIndicatorGraphSize.large,
|
|
72
|
+
},
|
|
73
|
+
},
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
export const Realtime: Story = {
|
|
77
|
+
tags: ['skip-test'],
|
|
78
|
+
args: {
|
|
79
|
+
data: [
|
|
80
|
+
Array.from({length: 60}, (_, i) => i),
|
|
81
|
+
Array.from(
|
|
82
|
+
{length: 60},
|
|
83
|
+
(_, i) => 2 + Math.sin((i / 60 / 5) * 2 * Math.PI)
|
|
84
|
+
),
|
|
85
|
+
],
|
|
86
|
+
layout: {
|
|
87
|
+
size: ObcIndicatorGraphSize.medium,
|
|
88
|
+
priority: ObcIndicatorGraphPriority.regular,
|
|
89
|
+
y: {max: 4},
|
|
90
|
+
},
|
|
91
|
+
},
|
|
92
|
+
play: async ({canvasElement}) => {
|
|
93
|
+
const graph = canvasElement.querySelector(
|
|
94
|
+
'obc-indicator-graph'
|
|
95
|
+
) as ObcIndicatorGraph;
|
|
96
|
+
if (!graph) {
|
|
97
|
+
throw new Error('Graph not found');
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
let i = graph.data[0].length;
|
|
101
|
+
const intervalId = setInterval(() => {
|
|
102
|
+
if (!graph.isConnected) {
|
|
103
|
+
clearInterval(intervalId);
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
const data = graph.data;
|
|
107
|
+
const x = [...data[0], i];
|
|
108
|
+
const y = [...data[1], 2 + Math.sin((i / 60 / 5) * 2 * Math.PI)];
|
|
109
|
+
x.shift();
|
|
110
|
+
y.shift();
|
|
111
|
+
const newData: [number[], number[]] = [x, y];
|
|
112
|
+
graph.data = newData;
|
|
113
|
+
i++;
|
|
114
|
+
}, 1000 / 60);
|
|
115
|
+
},
|
|
116
|
+
};
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
import {LitElement, PropertyValues, html, unsafeCSS} from 'lit';
|
|
2
|
+
import {property, query, state} from 'lit/decorators.js';
|
|
3
|
+
import compentStyle from './indicator-graph.css?inline';
|
|
4
|
+
import uPlot from 'uplot';
|
|
5
|
+
import {customElement} from '../../decorator.js';
|
|
6
|
+
|
|
7
|
+
export enum ObcIndicatorGraphSize {
|
|
8
|
+
small = 'small',
|
|
9
|
+
medium = 'medium',
|
|
10
|
+
large = 'large',
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export enum ObcIndicatorGraphPriority {
|
|
14
|
+
regular = 'regular',
|
|
15
|
+
enhanced = 'enhanced',
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export interface ObcIndicatorGraphLayout {
|
|
19
|
+
size?: ObcIndicatorGraphSize;
|
|
20
|
+
priority?: ObcIndicatorGraphPriority;
|
|
21
|
+
y?: {min?: number; max?: number};
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* @element obc-indicator-graph
|
|
26
|
+
* @description A mini graph component
|
|
27
|
+
*
|
|
28
|
+
* @property {Array} data - The data to display in the graph, first array is the x values, second array is the y values
|
|
29
|
+
*/
|
|
30
|
+
@customElement('obc-indicator-graph')
|
|
31
|
+
export class ObcIndicatorGraph extends LitElement {
|
|
32
|
+
@property({type: Array})
|
|
33
|
+
data: [number[], number[]] = [[], []];
|
|
34
|
+
|
|
35
|
+
@property({type: Object})
|
|
36
|
+
layout: ObcIndicatorGraphLayout = {};
|
|
37
|
+
|
|
38
|
+
@query('.chart-container')
|
|
39
|
+
private chart!: HTMLDivElement;
|
|
40
|
+
|
|
41
|
+
@state()
|
|
42
|
+
private y: number = 24;
|
|
43
|
+
|
|
44
|
+
@state()
|
|
45
|
+
private zeroLineY: number = 0;
|
|
46
|
+
|
|
47
|
+
private uplot: uPlot | null = null;
|
|
48
|
+
private resizeObserver: ResizeObserver | null = null;
|
|
49
|
+
|
|
50
|
+
private getCssColor(name: string) {
|
|
51
|
+
const color = getComputedStyle(this).getPropertyValue(name).trim();
|
|
52
|
+
return color;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
override firstUpdated() {
|
|
56
|
+
const opts = {
|
|
57
|
+
width: this.chart.clientWidth,
|
|
58
|
+
height: this.chart.clientHeight,
|
|
59
|
+
scales: {
|
|
60
|
+
x: {time: false, show: false},
|
|
61
|
+
y: {
|
|
62
|
+
auto: true,
|
|
63
|
+
show: false,
|
|
64
|
+
range: this._range.bind(this),
|
|
65
|
+
},
|
|
66
|
+
},
|
|
67
|
+
series: [
|
|
68
|
+
{},
|
|
69
|
+
{
|
|
70
|
+
stroke: this._getStrokeColor(),
|
|
71
|
+
width: this._getStrokeWidth(),
|
|
72
|
+
points: {show: false},
|
|
73
|
+
},
|
|
74
|
+
],
|
|
75
|
+
axes: [
|
|
76
|
+
{show: false},
|
|
77
|
+
{ticks: {show: false}, show: false, grid: {show: false}},
|
|
78
|
+
],
|
|
79
|
+
legend: {show: false},
|
|
80
|
+
cursor: {show: false},
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
this.uplot = new uPlot(opts, this.data, this.chart);
|
|
84
|
+
requestAnimationFrame(() => this.updateY());
|
|
85
|
+
|
|
86
|
+
this.resizeObserver = new ResizeObserver(() => this.updateSize());
|
|
87
|
+
this.resizeObserver.observe(this.chart);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
override disconnectedCallback() {
|
|
91
|
+
super.disconnectedCallback();
|
|
92
|
+
this.resizeObserver?.disconnect();
|
|
93
|
+
this.resizeObserver = null;
|
|
94
|
+
this.uplot?.destroy();
|
|
95
|
+
this.uplot = null;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
private updateSize() {
|
|
99
|
+
if (!this.uplot) {
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
this.uplot.setSize({
|
|
103
|
+
width: this.chart.clientWidth,
|
|
104
|
+
height: this.chart.clientHeight,
|
|
105
|
+
});
|
|
106
|
+
this.updateY();
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
private _range(
|
|
110
|
+
_self: uPlot,
|
|
111
|
+
initMin: number,
|
|
112
|
+
initMax: number,
|
|
113
|
+
_scaleKey: string
|
|
114
|
+
): [number, number] {
|
|
115
|
+
const {min: minY, max: maxY} = this.layout.y ?? {};
|
|
116
|
+
const range = maxY ?? initMax - (minY ?? initMin);
|
|
117
|
+
let min = minY ?? initMin - range * 0.1;
|
|
118
|
+
if (minY === undefined) {
|
|
119
|
+
min = Math.min(0, min);
|
|
120
|
+
}
|
|
121
|
+
return [min, maxY ?? initMax + range * 0.1] as [number, number];
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
private get _effectiveSize() {
|
|
125
|
+
return this.layout.size ?? ObcIndicatorGraphSize.medium;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
private get _effectivePriority() {
|
|
129
|
+
return this.layout.priority ?? ObcIndicatorGraphPriority.regular;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
private _getStrokeWidth() {
|
|
133
|
+
switch (this._effectiveSize) {
|
|
134
|
+
case ObcIndicatorGraphSize.small:
|
|
135
|
+
return 1;
|
|
136
|
+
case ObcIndicatorGraphSize.medium:
|
|
137
|
+
return 1.5;
|
|
138
|
+
case ObcIndicatorGraphSize.large:
|
|
139
|
+
return 2;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
private _getStrokeColor() {
|
|
144
|
+
switch (this._effectivePriority) {
|
|
145
|
+
case ObcIndicatorGraphPriority.regular:
|
|
146
|
+
return this.getCssColor('--element-neutral-color');
|
|
147
|
+
case ObcIndicatorGraphPriority.enhanced:
|
|
148
|
+
return this.getCssColor('--element-neutral-enhanced-color');
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
updatePalette() {
|
|
153
|
+
if (!this.uplot) {
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
const stroke = this._getStrokeColor();
|
|
157
|
+
this.uplot.setSeries(1, {
|
|
158
|
+
// @ts-expect-error - stroke is not a property of the Series interface
|
|
159
|
+
stroke: stroke,
|
|
160
|
+
width: this._getStrokeWidth(),
|
|
161
|
+
points: {show: false},
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
private updateY() {
|
|
166
|
+
if (!this.uplot) {
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
const lastY = this.data[1][this.data[1].length - 1];
|
|
170
|
+
// @ts-expect-error - valToPct is not a property of the Scale interface
|
|
171
|
+
const yRatio = this.uplot.scales.y.valToPct(lastY);
|
|
172
|
+
this.y = yRatio * this.chart.clientHeight;
|
|
173
|
+
this.updateZeroLine();
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
private updateZeroLine() {
|
|
177
|
+
if (!this.uplot) {
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
// @ts-expect-error - valToPct is not a property of the Scale interface
|
|
181
|
+
const yRatio = this.uplot.scales.y.valToPct(0);
|
|
182
|
+
this.zeroLineY = yRatio * this.chart.clientHeight;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
override updated(changedProperties: PropertyValues) {
|
|
186
|
+
if (changedProperties.has('data') || changedProperties.has('layout')) {
|
|
187
|
+
this.updatePalette();
|
|
188
|
+
this.uplot?.setData(this.data);
|
|
189
|
+
requestAnimationFrame(() => this.updateY());
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
override render() {
|
|
194
|
+
return html`
|
|
195
|
+
<div
|
|
196
|
+
class="chart-container ${this._effectivePriority} ${this
|
|
197
|
+
._effectiveSize}"
|
|
198
|
+
>
|
|
199
|
+
<div
|
|
200
|
+
id="zero-line"
|
|
201
|
+
style="transform: translateY(${-this.zeroLineY}px);
|
|
202
|
+
display: ${this.zeroLineY > -0.5 ? 'block' : 'none'};
|
|
203
|
+
"
|
|
204
|
+
></div>
|
|
205
|
+
<div
|
|
206
|
+
id="dot"
|
|
207
|
+
style="transform: translateY(${-this.y}px);
|
|
208
|
+
display: ${this.y > -0.5 ? 'block' : 'none'};
|
|
209
|
+
"
|
|
210
|
+
></div>
|
|
211
|
+
</div>
|
|
212
|
+
`;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
static override styles = unsafeCSS(compentStyle);
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
declare global {
|
|
219
|
+
interface HTMLElementTagNameMap {
|
|
220
|
+
'obc-indicator-graph': ObcIndicatorGraph;
|
|
221
|
+
}
|
|
222
|
+
}
|