Skip to content

Commit 022abb5

Browse files
author
Marko Petzold
committed
stabailze value rendering
1 parent e91016f commit 022abb5

3 files changed

Lines changed: 63 additions & 78 deletions

File tree

demo/index.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@
5353
document.getElementById('demo')
5454
)
5555
const widget = document.getElementById('demo').children[0]
56-
const keyPathsToRandomize = ['dataseries.0.data.0.value', 'settings.title']
56+
const keyPathsToRandomize = ['dataseries.0.value', 'settings.title']
5757
const inter = setInterval(() => {
5858
const randomizedObj = randomizeObjectValues(data, keyPathsToRandomize)
5959

src/default-data.json

Lines changed: 2 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -4,28 +4,12 @@
44
"label": "Temperature",
55
"unit": "°C",
66
"precision": 2,
7-
"styling": {},
8-
"advanced": {
9-
"averageLatest": 1
10-
},
11-
"data": [
12-
{
13-
"value": 90
14-
}
15-
]
7+
"value": 90
168
},
179
{
1810
"label": "Pressure",
1911
"unit": "Pa",
20-
"styling": {},
21-
"advanced": {
22-
"averageLatest": 1
23-
},
24-
"data": [
25-
{
26-
"value": 80
27-
}
28-
]
12+
"value": 80
2913
}
3014
]
3115
}

src/widget-value.ts

Lines changed: 60 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
import { html, css, LitElement, PropertyValueMap } from 'lit'
1+
import { html, css, LitElement, PropertyValueMap, PropertyValues } from 'lit'
22
import { repeat } from 'lit/directives/repeat.js'
3-
import { customElement, property, state } from 'lit/decorators.js'
3+
import { customElement, property, query, state } from 'lit/decorators.js'
44
import { InputData } from './definition-schema.js'
55

66
type Dataseries = Exclude<InputData['dataseries'], undefined>[number] & { needleValue?: number }
@@ -28,14 +28,19 @@ export class WidgetValue extends LitElement {
2828
@state() private themeTitleColor?: string
2929
@state() private themeSubtitleColor?: string
3030

31+
@query('.value-container')
32+
valueContainer?: HTMLDivElement
33+
34+
@query('.sizing-container')
35+
sizingContainer?: HTMLDivElement
36+
3137
version: string = 'versionplaceholder'
3238

3339
private resizeObserver: ResizeObserver
40+
private lastLargerWidthTime?: number
41+
private origWidth: number = 0
42+
private origHeight: number = 0
3443

35-
valueContainer?: HTMLDivElement
36-
boxes?: HTMLDivElement[]
37-
origWidth: number = 0
38-
origHeight: number = 0
3944
constructor() {
4045
super()
4146
this.resizeObserver = new ResizeObserver(this.applyData.bind(this))
@@ -50,26 +55,27 @@ export class WidgetValue extends LitElement {
5055
}
5156

5257
protected firstUpdated(_changedProperties: PropertyValueMap<any> | Map<PropertyKey, unknown>) {
53-
this.valueContainer = this?.shadowRoot?.querySelector('.value-container') as HTMLDivElement
54-
5558
this.registerTheme(this.theme)
56-
this.sizingSetup()
57-
this.transformData()
58-
this.applyData()
5959
}
6060

61-
update(changedProperties: Map<string, any>) {
61+
protected update(changedProperties: PropertyValues): void {
6262
if (changedProperties.has('inputData')) {
63-
this.sizingSetup()
6463
this.transformData()
64+
}
65+
super.update(changedProperties)
66+
}
67+
68+
protected updated(changedProperties: Map<string, any>) {
69+
if (changedProperties.has('inputData')) {
70+
this.sizingSetup()
6571
this.applyData()
6672
}
6773

6874
if (changedProperties.has('theme')) {
6975
this.registerTheme(this.theme)
7076
}
7177

72-
super.update(changedProperties)
78+
super.updated(changedProperties)
7379
}
7480

7581
registerTheme(theme?: Theme) {
@@ -83,20 +89,32 @@ export class WidgetValue extends LitElement {
8389

8490
sizingSetup() {
8591
const boxes = Array.from(
86-
this?.shadowRoot?.querySelectorAll(
87-
'.sizing-container > .single-value'
88-
) as NodeListOf<HTMLDivElement>
92+
this.sizingContainer?.querySelectorAll('.single-value') as NodeListOf<HTMLDivElement>
8993
)
9094

91-
this.origWidth =
92-
boxes?.map((b) => b.getBoundingClientRect().width).reduce((p, c) => (c > p ? c : p), 0) ?? 0
93-
this.origHeight =
94-
boxes?.map((b) => b.getBoundingClientRect().height).reduce((p, c) => (c > p ? c : p), 0) ?? 0
95+
let width = 0
96+
let height = 0
97+
for (const box of boxes) {
98+
const dims = box.getBoundingClientRect()
99+
width = Math.max(dims.width, width)
100+
height = Math.max(dims.height, height)
101+
}
102+
103+
if (width < this.origWidth) {
104+
if (!this.lastLargerWidthTime || Date.now() - this.lastLargerWidthTime > 5000) {
105+
this.origWidth = width
106+
}
107+
} else {
108+
this.origWidth = width
109+
this.lastLargerWidthTime = Date.now()
110+
}
111+
this.origHeight = height
95112
}
96113

97114
applyData() {
98-
const userWidth = this.valueContainer?.getBoundingClientRect().width
99-
const userHeight = this.valueContainer?.getBoundingClientRect().height
115+
if (!this.valueContainer) return
116+
const userWidth = this.valueContainer.getBoundingClientRect().width
117+
const userHeight = this.valueContainer.getBoundingClientRect().height
100118
const count = this.dataSets.size
101119

102120
const width = this.origWidth
@@ -110,7 +128,7 @@ export class WidgetValue extends LitElement {
110128
const uhgap = userHeight - 12 * (r - 1)
111129
const m = uwgap / width / c
112130
const size = m * m * width * height * count
113-
if (r * m * height <= uhgap) fits.push({ c, m, size, width, height, userWidth, userHeight })
131+
if (r * m * height <= uhgap) fits.push({ r, c, m, size, width, height, userWidth, userHeight })
114132
}
115133

116134
for (let r = 1; r <= count; r++) {
@@ -119,53 +137,47 @@ export class WidgetValue extends LitElement {
119137
const uhgap = userHeight - 12 * (r - 1)
120138
const m = uhgap / height / r
121139
const size = m * m * width * height * count
122-
if (c * m * width <= uwgap) fits.push({ r, m, size, width, height, userWidth, userHeight })
140+
if (c * m * width <= uwgap) fits.push({ r, c, m, size, width, height, userWidth, userHeight })
123141
}
124142
const maxSize = fits.reduce((p, c) => (c.size < p ? p : c.size), 0)
125143
const fit = fits.find((f) => f.size === maxSize)
126-
const modifier = fit?.m ?? 1
144+
if (!fit) return
145+
const modifier = fit.m ?? 1
127146
// console.log('FITS', fits, 'modifier', modifier, 'cols',fit?.c, 'rows', fit?.r, 'new size', fit?.size.toFixed(0), 'total space', (userWidth* userHeight).toFixed(0))
128-
129147
const boxes = Array.from(
130-
this?.shadowRoot?.querySelectorAll(
131-
'.value-container > .single-value'
132-
) as NodeListOf<HTMLDivElement>
148+
this.valueContainer?.querySelectorAll('.single-value') as NodeListOf<HTMLDivElement>
133149
)
150+
this.valueContainer.style.gridTemplateColumns = `repeat(${fit.c}, 1fr)`
134151

135-
boxes?.forEach((box) =>
152+
for (const box of boxes) {
136153
box.setAttribute(
137154
'style',
138155
`width:${modifier * width}px; height:${modifier * height}px; padding:${modifier * 6}px`
139156
)
140-
)
141157

142-
boxes?.forEach((n) => {
143-
const label: string | null = n.getAttribute('label')
158+
const label: string | null = box.getAttribute('label')
144159
const ds: Dataseries | undefined = this.dataSets.get(label ?? '')
145-
const numberText = n.querySelector('.current-value') as HTMLDivElement
160+
161+
const numberText = box.querySelector('.current-value') as HTMLDivElement
146162
numberText.setAttribute(
147163
'style',
148164
`font-size: ${32 * modifier}px;
149165
color: ${ds?.styling?.valueColor || this.theme?.theme_object?.color?.[0] || this.themeTitleColor};`
150166
)
151-
})
152167

153-
boxes?.forEach((n) => {
154-
const label: string | null = n.getAttribute('label')
155-
const ds: Dataseries | undefined = this.dataSets.get(label ?? '')
156-
const labelText = n.querySelector('.label') as HTMLDivElement
168+
const labelText = box.querySelector('.label') as HTMLDivElement
157169
labelText.setAttribute(
158170
'style',
159171
`font-size: ${26 * modifier}px;
160172
color: ${ds?.styling?.labelColor || this.theme?.theme_object?.color?.[1] || this.themeSubtitleColor};`
161173
)
162-
const unitText = n.querySelector('.unit') as HTMLDivElement
174+
const unitText = box.querySelector('.unit') as HTMLDivElement
163175
unitText.setAttribute(
164176
'style',
165177
`font-size: ${26 * modifier}px;
166178
color: ${ds?.styling?.valueColor || this.theme?.theme_object?.color?.[0] || this.themeTitleColor};`
167179
)
168-
})
180+
}
169181

170182
this.textActive = true
171183
}
@@ -180,8 +192,10 @@ export class WidgetValue extends LitElement {
180192
// ?.sort((a, b) => a.order - b.order)
181193
?.forEach((ds) => {
182194
// pivot data
183-
const distincts = [...new Set(ds.data?.map((d: Data) => d.pivot))].sort() as string[]
184-
ds.needleValue = undefined
195+
const distincts = ds.multiChart
196+
? ([...new Set(ds.data?.map((d: Data) => d.pivot))].sort() as string[])
197+
: ['']
198+
185199
distincts.forEach((piv) => {
186200
const prefix = piv ?? ''
187201
const label = ds.label ?? ''
@@ -221,10 +235,6 @@ export class WidgetValue extends LitElement {
221235
}
222236
}
223237
})
224-
225-
this.requestUpdate()
226-
await this.updateComplete
227-
// console.log('Value Datasets', this.dataSets)
228238
}
229239

230240
static styles = css`
@@ -267,10 +277,7 @@ export class WidgetValue extends LitElement {
267277
}
268278
269279
.value-container {
270-
display: flex;
271-
flex-wrap: wrap;
272-
align-items: center;
273-
justify-content: center;
280+
display: grid;
274281
line-height: 0.9;
275282
flex: 1;
276283
overflow: hidden;
@@ -284,7 +291,6 @@ export class WidgetValue extends LitElement {
284291
align-items: end;
285292
padding: 6px;
286293
box-sizing: border-box;
287-
/* border-left: 4px solid #ddd; */
288294
}
289295
290296
.current-value {
@@ -302,13 +308,8 @@ export class WidgetValue extends LitElement {
302308
303309
.sizing-container {
304310
position: absolute;
305-
left: 10000px;
306-
display: flex;
311+
left: 100000px;
307312
line-height: 0.9;
308-
flex-wrap: wrap;
309-
align-items: center;
310-
justify-content: center;
311-
flex: 1;
312313
overflow: hidden;
313314
gap: 12px;
314315
}

0 commit comments

Comments
 (0)