gaugeit.js 0.1.0 → 0.1.1
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/README.md +51 -27
- package/SECURITY.md +2 -2
- package/dist/gaugeit.cjs +158 -104
- package/dist/gaugeit.cjs.map +3 -3
- package/dist/gaugeit.css +32 -20
- package/dist/gaugeit.d.ts +17 -0
- package/dist/gaugeit.esm.js +158 -104
- package/dist/gaugeit.esm.js.map +3 -3
- package/dist/gaugeit.esm.min.js +2 -2
- package/dist/gaugeit.esm.min.js.map +3 -3
- package/dist/gaugeit.min.cjs +2 -2
- package/dist/gaugeit.min.cjs.map +3 -3
- package/dist/gaugeit.min.css +1 -1
- package/dist/gaugeit.standalone.js +159 -105
- package/dist/gaugeit.standalone.js.map +3 -3
- package/dist/gaugeit.standalone.min.js +35 -23
- package/dist/gaugeit.standalone.min.js.map +3 -3
- package/dist/gaugeit.umd.js +158 -104
- package/dist/gaugeit.umd.js.map +3 -3
- package/dist/gaugeit.umd.min.js +2 -2
- package/dist/gaugeit.umd.min.js.map +3 -3
- package/dist/manifest.json +20 -20
- package/docs/ai/ai-full.md +5097 -0
- package/docs/ai/contributor-guide.md +928 -0
- package/docs/ai/index.md +73 -0
- package/docs/ai/integration-recipes.md +1117 -0
- package/docs/ai/library-usage.md +875 -0
- package/docs/ai/options-reference.md +1107 -0
- package/docs/ai/troubleshooting.md +1024 -0
- package/docs/api.md +34 -7
- package/docs/architecture.md +10 -2
- package/docs/creating-gauge-types.md +2 -1
- package/docs/development.md +2 -2
- package/docs/framework-integration.md +2 -2
- package/package.json +1 -1
|
@@ -0,0 +1,1117 @@
|
|
|
1
|
+
# Gaugeit.js integration recipes
|
|
2
|
+
|
|
3
|
+
These recipes target Gaugeit.js 0.1.1. Each recipe is intended to be copied as a
|
|
4
|
+
complete starting point. Replace application values and labels, but preserve package
|
|
5
|
+
names, import paths, global names, lifecycle cleanup, and option nesting.
|
|
6
|
+
|
|
7
|
+
## 1. Simple semicircular gauge in plain HTML
|
|
8
|
+
|
|
9
|
+
Save as `index.html` beside `dist/`:
|
|
10
|
+
|
|
11
|
+
```html
|
|
12
|
+
<!doctype html>
|
|
13
|
+
<html lang="en">
|
|
14
|
+
<head>
|
|
15
|
+
<meta charset="utf-8">
|
|
16
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
17
|
+
<title>Gaugeit.js arc gauge</title>
|
|
18
|
+
<link rel="stylesheet" href="./dist/gaugeit.min.css">
|
|
19
|
+
<style>
|
|
20
|
+
body {
|
|
21
|
+
max-width: 42rem;
|
|
22
|
+
margin: 2rem auto;
|
|
23
|
+
padding: 0 1rem;
|
|
24
|
+
font-family: system-ui, sans-serif;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
#load-gauge {
|
|
28
|
+
width: min(100%, 32rem);
|
|
29
|
+
margin-inline: auto;
|
|
30
|
+
}
|
|
31
|
+
</style>
|
|
32
|
+
</head>
|
|
33
|
+
<body>
|
|
34
|
+
<h1>Engine load</h1>
|
|
35
|
+
<div id="load-gauge"></div>
|
|
36
|
+
|
|
37
|
+
<script src="./dist/gaugeit.umd.min.js"></script>
|
|
38
|
+
<script>
|
|
39
|
+
const gauge = Gaugeit.createGauge('#load-gauge', {
|
|
40
|
+
type: 'arc',
|
|
41
|
+
min: 0,
|
|
42
|
+
max: 100,
|
|
43
|
+
value: 42,
|
|
44
|
+
zones: [
|
|
45
|
+
{ min: 0, max: 60, color: '#22c55e' },
|
|
46
|
+
{ min: 60, max: 85, color: '#facc15' },
|
|
47
|
+
{ min: 85, max: 100, color: '#ef4444' }
|
|
48
|
+
],
|
|
49
|
+
readout: {
|
|
50
|
+
title: {
|
|
51
|
+
visible: true,
|
|
52
|
+
text: 'ENGINE LOAD'
|
|
53
|
+
},
|
|
54
|
+
value: {
|
|
55
|
+
visible: true,
|
|
56
|
+
suffix: '%'
|
|
57
|
+
}
|
|
58
|
+
},
|
|
59
|
+
accessibility: {
|
|
60
|
+
label: 'Engine load',
|
|
61
|
+
valueText: (value) => `${Math.round(value)} percent`
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
window.setTimeout(() => {
|
|
66
|
+
gauge.setValue(76);
|
|
67
|
+
}, 1000);
|
|
68
|
+
</script>
|
|
69
|
+
</body>
|
|
70
|
+
</html>
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## 2. Classic framed instrument
|
|
74
|
+
|
|
75
|
+
```html
|
|
76
|
+
<!doctype html>
|
|
77
|
+
<html lang="en">
|
|
78
|
+
<head>
|
|
79
|
+
<meta charset="utf-8">
|
|
80
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
81
|
+
<title>Classic Gaugeit.js instrument</title>
|
|
82
|
+
<link rel="stylesheet" href="./dist/gaugeit.min.css">
|
|
83
|
+
<style>
|
|
84
|
+
#voltage-gauge {
|
|
85
|
+
width: min(100%, 34rem);
|
|
86
|
+
margin: 2rem auto;
|
|
87
|
+
}
|
|
88
|
+
</style>
|
|
89
|
+
</head>
|
|
90
|
+
<body>
|
|
91
|
+
<div id="voltage-gauge"></div>
|
|
92
|
+
|
|
93
|
+
<script src="./dist/gaugeit.umd.min.js"></script>
|
|
94
|
+
<script>
|
|
95
|
+
const voltageGauge = Gaugeit.createGauge('#voltage-gauge', {
|
|
96
|
+
type: 'classic',
|
|
97
|
+
min: 0,
|
|
98
|
+
max: 240,
|
|
99
|
+
value: 118,
|
|
100
|
+
zones: [
|
|
101
|
+
{ min: 0, max: 90, color: '#ef4444', width: 12 },
|
|
102
|
+
{ min: 90, max: 150, color: '#22c55e', width: 12 },
|
|
103
|
+
{ min: 150, max: 240, color: '#ef4444', width: 12 }
|
|
104
|
+
],
|
|
105
|
+
pointer: {
|
|
106
|
+
type: 'spear',
|
|
107
|
+
colorByZone: true
|
|
108
|
+
},
|
|
109
|
+
readout: {
|
|
110
|
+
title: {
|
|
111
|
+
visible: true,
|
|
112
|
+
text: 'VOLTAGE'
|
|
113
|
+
},
|
|
114
|
+
value: {
|
|
115
|
+
visible: true,
|
|
116
|
+
fractionDigits: 0
|
|
117
|
+
},
|
|
118
|
+
unit: {
|
|
119
|
+
visible: true,
|
|
120
|
+
text: 'V'
|
|
121
|
+
}
|
|
122
|
+
},
|
|
123
|
+
accessibility: {
|
|
124
|
+
label: 'Voltage',
|
|
125
|
+
valueText: (value) => `${Math.round(value)} volts`
|
|
126
|
+
}
|
|
127
|
+
});
|
|
128
|
+
</script>
|
|
129
|
+
</body>
|
|
130
|
+
</html>
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
## 3. Radial center-zero balance gauge
|
|
134
|
+
|
|
135
|
+
```html
|
|
136
|
+
<!doctype html>
|
|
137
|
+
<html lang="en">
|
|
138
|
+
<head>
|
|
139
|
+
<meta charset="utf-8">
|
|
140
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
141
|
+
<title>Center-zero Gaugeit.js gauge</title>
|
|
142
|
+
<link rel="stylesheet" href="./dist/gaugeit.min.css">
|
|
143
|
+
</head>
|
|
144
|
+
<body>
|
|
145
|
+
<div id="balance-gauge"></div>
|
|
146
|
+
|
|
147
|
+
<script src="./dist/gaugeit.umd.min.js"></script>
|
|
148
|
+
<script>
|
|
149
|
+
const balanceGauge = Gaugeit.createGauge('#balance-gauge', {
|
|
150
|
+
type: 'center-zero',
|
|
151
|
+
min: -100,
|
|
152
|
+
max: 100,
|
|
153
|
+
value: -18,
|
|
154
|
+
centerZero: {
|
|
155
|
+
zeroValue: 0,
|
|
156
|
+
symmetric: true,
|
|
157
|
+
marker: {
|
|
158
|
+
visible: true
|
|
159
|
+
}
|
|
160
|
+
},
|
|
161
|
+
zones: [
|
|
162
|
+
{ min: -100, max: -60, color: '#ef4444' },
|
|
163
|
+
{ min: -60, max: 60, color: '#22c55e' },
|
|
164
|
+
{ min: 60, max: 100, color: '#ef4444' }
|
|
165
|
+
],
|
|
166
|
+
readout: {
|
|
167
|
+
title: {
|
|
168
|
+
visible: true,
|
|
169
|
+
text: 'BALANCE'
|
|
170
|
+
},
|
|
171
|
+
value: {
|
|
172
|
+
visible: true,
|
|
173
|
+
prefix: ''
|
|
174
|
+
}
|
|
175
|
+
},
|
|
176
|
+
accessibility: {
|
|
177
|
+
label: 'Balance deviation',
|
|
178
|
+
valueText: (value) => `${Math.round(value)} balance units`
|
|
179
|
+
}
|
|
180
|
+
});
|
|
181
|
+
</script>
|
|
182
|
+
</body>
|
|
183
|
+
</html>
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
The numeric range contains `zeroValue`. `symmetric: true` protects the centered
|
|
187
|
+
reference if the supplied endpoints are uneven.
|
|
188
|
+
|
|
189
|
+
## 4. Classic linear center-zero instrument
|
|
190
|
+
|
|
191
|
+
```html
|
|
192
|
+
<!doctype html>
|
|
193
|
+
<html lang="en">
|
|
194
|
+
<head>
|
|
195
|
+
<meta charset="utf-8">
|
|
196
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
197
|
+
<title>Classic linear center-zero instrument</title>
|
|
198
|
+
<link rel="stylesheet" href="./dist/gaugeit.min.css">
|
|
199
|
+
<style>
|
|
200
|
+
#trim-gauge {
|
|
201
|
+
width: min(100%, 42rem);
|
|
202
|
+
margin: 2rem auto;
|
|
203
|
+
}
|
|
204
|
+
</style>
|
|
205
|
+
</head>
|
|
206
|
+
<body>
|
|
207
|
+
<div id="trim-gauge"></div>
|
|
208
|
+
|
|
209
|
+
<script src="./dist/gaugeit.umd.min.js"></script>
|
|
210
|
+
<script>
|
|
211
|
+
const trimGauge = Gaugeit.createGauge('#trim-gauge', {
|
|
212
|
+
type: 'classic-linear-zero',
|
|
213
|
+
min: -50,
|
|
214
|
+
max: 50,
|
|
215
|
+
value: 12,
|
|
216
|
+
centerZero: {
|
|
217
|
+
zeroValue: 0,
|
|
218
|
+
symmetric: true,
|
|
219
|
+
marker: {
|
|
220
|
+
visible: true,
|
|
221
|
+
color: '#111827'
|
|
222
|
+
}
|
|
223
|
+
},
|
|
224
|
+
indicator: {
|
|
225
|
+
type: 'hairline',
|
|
226
|
+
color: '#b91c1c',
|
|
227
|
+
centerOffset: 0
|
|
228
|
+
},
|
|
229
|
+
readout: {
|
|
230
|
+
title: {
|
|
231
|
+
visible: true,
|
|
232
|
+
text: 'TRIM'
|
|
233
|
+
},
|
|
234
|
+
value: {
|
|
235
|
+
visible: true,
|
|
236
|
+
fractionDigits: 0
|
|
237
|
+
}
|
|
238
|
+
},
|
|
239
|
+
accessibility: {
|
|
240
|
+
label: 'Trim setting'
|
|
241
|
+
}
|
|
242
|
+
});
|
|
243
|
+
</script>
|
|
244
|
+
</body>
|
|
245
|
+
</html>
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
Public linear Y and center offsets are positive-up, not raw SVG coordinates.
|
|
249
|
+
|
|
250
|
+
## 5. Rolling tape gauge
|
|
251
|
+
|
|
252
|
+
```html
|
|
253
|
+
<!doctype html>
|
|
254
|
+
<html lang="en">
|
|
255
|
+
<head>
|
|
256
|
+
<meta charset="utf-8">
|
|
257
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
258
|
+
<title>Gaugeit.js rolling tape</title>
|
|
259
|
+
<link rel="stylesheet" href="./dist/gaugeit.min.css">
|
|
260
|
+
<style>
|
|
261
|
+
#altitude-tape {
|
|
262
|
+
width: min(100%, 20rem);
|
|
263
|
+
margin: 2rem auto;
|
|
264
|
+
}
|
|
265
|
+
</style>
|
|
266
|
+
</head>
|
|
267
|
+
<body>
|
|
268
|
+
<div id="altitude-tape"></div>
|
|
269
|
+
|
|
270
|
+
<script src="./dist/gaugeit.umd.min.js"></script>
|
|
271
|
+
<script>
|
|
272
|
+
const altitudeTape = Gaugeit.createGauge('#altitude-tape', {
|
|
273
|
+
type: 'rolling-tape',
|
|
274
|
+
min: 0,
|
|
275
|
+
max: 40000,
|
|
276
|
+
value: 12500,
|
|
277
|
+
tape: {
|
|
278
|
+
orientation: 'vertical',
|
|
279
|
+
interval: 1000,
|
|
280
|
+
minorSubdivisions: 4,
|
|
281
|
+
majorSpacing: 54,
|
|
282
|
+
indicatorColor: '#b91c1c',
|
|
283
|
+
colorByZone: true
|
|
284
|
+
},
|
|
285
|
+
zones: [
|
|
286
|
+
{ min: 0, max: 10000, color: '#22c55e' },
|
|
287
|
+
{ min: 10000, max: 25000, color: '#facc15' },
|
|
288
|
+
{ min: 25000, max: 40000, color: '#ef4444' }
|
|
289
|
+
],
|
|
290
|
+
readout: {
|
|
291
|
+
title: {
|
|
292
|
+
visible: true,
|
|
293
|
+
text: 'ALTITUDE'
|
|
294
|
+
},
|
|
295
|
+
unit: {
|
|
296
|
+
visible: true,
|
|
297
|
+
text: 'ft'
|
|
298
|
+
}
|
|
299
|
+
},
|
|
300
|
+
accessibility: {
|
|
301
|
+
label: 'Altitude',
|
|
302
|
+
valueText: (value) => `${Math.round(value)} feet`
|
|
303
|
+
}
|
|
304
|
+
});
|
|
305
|
+
|
|
306
|
+
altitudeTape.setValue(13800, {
|
|
307
|
+
duration: 1400
|
|
308
|
+
});
|
|
309
|
+
</script>
|
|
310
|
+
</body>
|
|
311
|
+
</html>
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
The tape moves behind its fixed reference line. Do not add a radial pointer to this
|
|
315
|
+
type.
|
|
316
|
+
|
|
317
|
+
## 6. Dynamic value stream
|
|
318
|
+
|
|
319
|
+
Use `setValue()` rather than rebuilding options for each sample:
|
|
320
|
+
|
|
321
|
+
```html
|
|
322
|
+
<!doctype html>
|
|
323
|
+
<html lang="en">
|
|
324
|
+
<head>
|
|
325
|
+
<meta charset="utf-8">
|
|
326
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
327
|
+
<title>Dynamic Gaugeit.js value</title>
|
|
328
|
+
<link rel="stylesheet" href="./dist/gaugeit.min.css">
|
|
329
|
+
</head>
|
|
330
|
+
<body>
|
|
331
|
+
<div id="live-gauge"></div>
|
|
332
|
+
<button id="stop" type="button">Stop updates</button>
|
|
333
|
+
|
|
334
|
+
<script src="./dist/gaugeit.umd.min.js"></script>
|
|
335
|
+
<script>
|
|
336
|
+
const gauge = Gaugeit.createGauge('#live-gauge', {
|
|
337
|
+
type: 'line-scale',
|
|
338
|
+
min: 0,
|
|
339
|
+
max: 100,
|
|
340
|
+
value: 50,
|
|
341
|
+
animation: {
|
|
342
|
+
duration: 400
|
|
343
|
+
},
|
|
344
|
+
readout: {
|
|
345
|
+
title: {
|
|
346
|
+
visible: true,
|
|
347
|
+
text: 'LIVE VALUE'
|
|
348
|
+
},
|
|
349
|
+
value: {
|
|
350
|
+
visible: true
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
});
|
|
354
|
+
|
|
355
|
+
const timer = window.setInterval(() => {
|
|
356
|
+
const nextValue = Math.round(Math.random() * 100);
|
|
357
|
+
gauge.setValue(nextValue);
|
|
358
|
+
}, 1000);
|
|
359
|
+
|
|
360
|
+
document.querySelector('#stop').addEventListener('click', () => {
|
|
361
|
+
window.clearInterval(timer);
|
|
362
|
+
gauge.destroy();
|
|
363
|
+
}, { once: true });
|
|
364
|
+
</script>
|
|
365
|
+
</body>
|
|
366
|
+
</html>
|
|
367
|
+
```
|
|
368
|
+
|
|
369
|
+
Application-owned timers remain application-owned and must be cleaned up separately
|
|
370
|
+
from the gauge.
|
|
371
|
+
|
|
372
|
+
## 7. Multiple gauges on one page
|
|
373
|
+
|
|
374
|
+
```html
|
|
375
|
+
<!doctype html>
|
|
376
|
+
<html lang="en">
|
|
377
|
+
<head>
|
|
378
|
+
<meta charset="utf-8">
|
|
379
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
380
|
+
<title>Multiple Gaugeit.js instruments</title>
|
|
381
|
+
<link rel="stylesheet" href="./dist/gaugeit.min.css">
|
|
382
|
+
<style>
|
|
383
|
+
.gauge-grid {
|
|
384
|
+
display: grid;
|
|
385
|
+
grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr));
|
|
386
|
+
gap: 1rem;
|
|
387
|
+
}
|
|
388
|
+
</style>
|
|
389
|
+
</head>
|
|
390
|
+
<body>
|
|
391
|
+
<div class="gauge-grid">
|
|
392
|
+
<div id="speed"></div>
|
|
393
|
+
<div id="temperature"></div>
|
|
394
|
+
<div id="balance"></div>
|
|
395
|
+
</div>
|
|
396
|
+
|
|
397
|
+
<script src="./dist/gaugeit.umd.min.js"></script>
|
|
398
|
+
<script>
|
|
399
|
+
const gauges = [
|
|
400
|
+
Gaugeit.createGauge('#speed', {
|
|
401
|
+
type: 'arc',
|
|
402
|
+
min: 0,
|
|
403
|
+
max: 240,
|
|
404
|
+
value: 88,
|
|
405
|
+
accessibility: { label: 'Speed' }
|
|
406
|
+
}),
|
|
407
|
+
|
|
408
|
+
Gaugeit.createGauge('#temperature', {
|
|
409
|
+
type: 'classic',
|
|
410
|
+
min: -20,
|
|
411
|
+
max: 120,
|
|
412
|
+
value: 68,
|
|
413
|
+
accessibility: { label: 'Temperature' }
|
|
414
|
+
}),
|
|
415
|
+
|
|
416
|
+
Gaugeit.createGauge('#balance', {
|
|
417
|
+
type: 'center-zero',
|
|
418
|
+
min: -100,
|
|
419
|
+
max: 100,
|
|
420
|
+
value: 6,
|
|
421
|
+
accessibility: { label: 'Balance' }
|
|
422
|
+
})
|
|
423
|
+
];
|
|
424
|
+
|
|
425
|
+
window.addEventListener('pagehide', () => {
|
|
426
|
+
for (const gauge of gauges) {
|
|
427
|
+
gauge.destroy();
|
|
428
|
+
}
|
|
429
|
+
}, { once: true });
|
|
430
|
+
</script>
|
|
431
|
+
</body>
|
|
432
|
+
</html>
|
|
433
|
+
```
|
|
434
|
+
|
|
435
|
+
Each gauge owns one host. Do not reuse one instance across several hosts.
|
|
436
|
+
|
|
437
|
+
## 8. Threshold warning light
|
|
438
|
+
|
|
439
|
+
```js
|
|
440
|
+
const gauge = Gaugeit.createGauge('#temperature', {
|
|
441
|
+
type: 'heritage-round',
|
|
442
|
+
min: 0,
|
|
443
|
+
max: 120,
|
|
444
|
+
value: 72,
|
|
445
|
+
light: {
|
|
446
|
+
visible: true,
|
|
447
|
+
x: 160,
|
|
448
|
+
y: 88,
|
|
449
|
+
radius: 8,
|
|
450
|
+
glowRadius: 24,
|
|
451
|
+
color: 'red',
|
|
452
|
+
pulse: false,
|
|
453
|
+
blink: false,
|
|
454
|
+
flicker: false,
|
|
455
|
+
trigger: {
|
|
456
|
+
mode: 'above',
|
|
457
|
+
source: 'target',
|
|
458
|
+
value: 95
|
|
459
|
+
}
|
|
460
|
+
},
|
|
461
|
+
accessibility: {
|
|
462
|
+
label: 'Coolant temperature'
|
|
463
|
+
}
|
|
464
|
+
});
|
|
465
|
+
```
|
|
466
|
+
|
|
467
|
+
`source: 'target'` makes the warning react to application intent immediately, without
|
|
468
|
+
waiting for pointer animation.
|
|
469
|
+
|
|
470
|
+
## 9. Pulsing active light
|
|
471
|
+
|
|
472
|
+
```js
|
|
473
|
+
const gauge = Gaugeit.createGauge('#status', {
|
|
474
|
+
type: 'classic',
|
|
475
|
+
value: 50,
|
|
476
|
+
light: {
|
|
477
|
+
visible: true,
|
|
478
|
+
x: 250,
|
|
479
|
+
y: 55,
|
|
480
|
+
radius: 8,
|
|
481
|
+
glowRadius: 26,
|
|
482
|
+
glowSharpness: 0.15,
|
|
483
|
+
glowOpacity: 0.2,
|
|
484
|
+
color: 'green',
|
|
485
|
+
on: true,
|
|
486
|
+
glow: true,
|
|
487
|
+
pulse: true,
|
|
488
|
+
pulseInterval: 2600,
|
|
489
|
+
blink: false,
|
|
490
|
+
flicker: false,
|
|
491
|
+
trigger: {
|
|
492
|
+
mode: 'manual'
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
});
|
|
496
|
+
```
|
|
497
|
+
|
|
498
|
+
The light must be active before pulse is visible. `on` controls the state only in
|
|
499
|
+
manual trigger mode.
|
|
500
|
+
|
|
501
|
+
## 10. Blinking warning light with flicker
|
|
502
|
+
|
|
503
|
+
```js
|
|
504
|
+
const gauge = Gaugeit.createGauge('#pressure', {
|
|
505
|
+
type: 'classic',
|
|
506
|
+
min: 0,
|
|
507
|
+
max: 10,
|
|
508
|
+
value: 4.2,
|
|
509
|
+
light: {
|
|
510
|
+
visible: true,
|
|
511
|
+
color: 'amber',
|
|
512
|
+
radius: 8,
|
|
513
|
+
glowRadius: 22,
|
|
514
|
+
glowOpacity: 0.18,
|
|
515
|
+
pulse: true,
|
|
516
|
+
blink: true,
|
|
517
|
+
blinkInterval: 900,
|
|
518
|
+
flicker: true,
|
|
519
|
+
flickerIntensity: 0.08,
|
|
520
|
+
flickerGlowRadius: 0.06,
|
|
521
|
+
flickerMinInterval: 55,
|
|
522
|
+
flickerMaxInterval: 150,
|
|
523
|
+
trigger: {
|
|
524
|
+
mode: 'below',
|
|
525
|
+
source: 'displayed',
|
|
526
|
+
value: 2
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
});
|
|
530
|
+
```
|
|
531
|
+
|
|
532
|
+
Blink takes precedence over pulse. Flicker remains an independent overlay. Browsers
|
|
533
|
+
requesting reduced motion receive a steady accessible state instead of motion.
|
|
534
|
+
|
|
535
|
+
## 11. React controlled component
|
|
536
|
+
|
|
537
|
+
```jsx
|
|
538
|
+
import { useMemo, useState } from 'react';
|
|
539
|
+
import Gaugeit from 'gaugeit.js/react';
|
|
540
|
+
import 'gaugeit.js/css';
|
|
541
|
+
|
|
542
|
+
export default function EngineLoadGauge() {
|
|
543
|
+
const [value, setValue] = useState(42);
|
|
544
|
+
|
|
545
|
+
const options = useMemo(() => ({
|
|
546
|
+
type: 'arc',
|
|
547
|
+
min: 0,
|
|
548
|
+
max: 100,
|
|
549
|
+
zones: [
|
|
550
|
+
{ min: 0, max: 60, color: '#22c55e' },
|
|
551
|
+
{ min: 60, max: 85, color: '#facc15' },
|
|
552
|
+
{ min: 85, max: 100, color: '#ef4444' }
|
|
553
|
+
],
|
|
554
|
+
readout: {
|
|
555
|
+
title: {
|
|
556
|
+
visible: true,
|
|
557
|
+
text: 'ENGINE LOAD'
|
|
558
|
+
},
|
|
559
|
+
value: {
|
|
560
|
+
visible: true,
|
|
561
|
+
suffix: '%'
|
|
562
|
+
}
|
|
563
|
+
},
|
|
564
|
+
accessibility: {
|
|
565
|
+
label: 'Engine load',
|
|
566
|
+
valueText: (current) => `${Math.round(current)} percent`
|
|
567
|
+
}
|
|
568
|
+
}), []);
|
|
569
|
+
|
|
570
|
+
return (
|
|
571
|
+
<section>
|
|
572
|
+
<Gaugeit
|
|
573
|
+
value={value}
|
|
574
|
+
options={options}
|
|
575
|
+
className="engine-load-gauge"
|
|
576
|
+
/>
|
|
577
|
+
|
|
578
|
+
<label>
|
|
579
|
+
Load
|
|
580
|
+
<input
|
|
581
|
+
type="range"
|
|
582
|
+
min="0"
|
|
583
|
+
max="100"
|
|
584
|
+
value={value}
|
|
585
|
+
onChange={(event) => setValue(Number(event.target.value))}
|
|
586
|
+
/>
|
|
587
|
+
</label>
|
|
588
|
+
</section>
|
|
589
|
+
);
|
|
590
|
+
}
|
|
591
|
+
```
|
|
592
|
+
|
|
593
|
+
The explicit `value` prop remains authoritative even if `options` also contains a
|
|
594
|
+
value. Prefer not to duplicate it.
|
|
595
|
+
|
|
596
|
+
## 12. React ref and imperative API
|
|
597
|
+
|
|
598
|
+
```jsx
|
|
599
|
+
import { useMemo, useRef } from 'react';
|
|
600
|
+
import Gaugeit from 'gaugeit.js/react';
|
|
601
|
+
import 'gaugeit.js/css';
|
|
602
|
+
|
|
603
|
+
export default function ImperativeGauge() {
|
|
604
|
+
const gaugeRef = useRef(null);
|
|
605
|
+
|
|
606
|
+
const options = useMemo(() => ({
|
|
607
|
+
type: 'classic',
|
|
608
|
+
min: 0,
|
|
609
|
+
max: 100,
|
|
610
|
+
value: 25,
|
|
611
|
+
accessibility: {
|
|
612
|
+
label: 'Imperative demonstration gauge'
|
|
613
|
+
}
|
|
614
|
+
}), []);
|
|
615
|
+
|
|
616
|
+
function setWarningValue() {
|
|
617
|
+
gaugeRef.current?.setValue(90, {
|
|
618
|
+
duration: 1200,
|
|
619
|
+
easing: 'easeInOutCubic'
|
|
620
|
+
});
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
function changeTheme() {
|
|
624
|
+
gaugeRef.current?.updateOptions({
|
|
625
|
+
pointer: {
|
|
626
|
+
color: '#dc2626'
|
|
627
|
+
},
|
|
628
|
+
face: {
|
|
629
|
+
color: '#fff7ed'
|
|
630
|
+
}
|
|
631
|
+
});
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
return (
|
|
635
|
+
<div>
|
|
636
|
+
<Gaugeit
|
|
637
|
+
ref={gaugeRef}
|
|
638
|
+
options={options}
|
|
639
|
+
/>
|
|
640
|
+
|
|
641
|
+
<button type="button" onClick={setWarningValue}>
|
|
642
|
+
Set warning value
|
|
643
|
+
</button>
|
|
644
|
+
|
|
645
|
+
<button type="button" onClick={changeTheme}>
|
|
646
|
+
Change theme
|
|
647
|
+
</button>
|
|
648
|
+
</div>
|
|
649
|
+
);
|
|
650
|
+
}
|
|
651
|
+
```
|
|
652
|
+
|
|
653
|
+
The adapter destroys the live instance on unmount. Do not call `destroy()` manually
|
|
654
|
+
from ordinary component cleanup unless the component owns a separately created
|
|
655
|
+
instance outside the adapter.
|
|
656
|
+
|
|
657
|
+
## 13. Laravel Composer asset installation
|
|
658
|
+
|
|
659
|
+
Install:
|
|
660
|
+
|
|
661
|
+
```bash
|
|
662
|
+
composer require kasperi/gaugeit-js:^0.1
|
|
663
|
+
vendor/bin/gaugeit-install-assets public/assets/vendor/gaugeit
|
|
664
|
+
```
|
|
665
|
+
|
|
666
|
+
Optional consuming-project automation:
|
|
667
|
+
|
|
668
|
+
```json
|
|
669
|
+
{
|
|
670
|
+
"scripts": {
|
|
671
|
+
"assets:gaugeit": "vendor/bin/gaugeit-install-assets public/assets/vendor/gaugeit",
|
|
672
|
+
"post-install-cmd": [
|
|
673
|
+
"@assets:gaugeit"
|
|
674
|
+
],
|
|
675
|
+
"post-update-cmd": [
|
|
676
|
+
"@assets:gaugeit"
|
|
677
|
+
]
|
|
678
|
+
}
|
|
679
|
+
}
|
|
680
|
+
```
|
|
681
|
+
|
|
682
|
+
Blade view:
|
|
683
|
+
|
|
684
|
+
```blade
|
|
685
|
+
@push('styles')
|
|
686
|
+
<link
|
|
687
|
+
rel="stylesheet"
|
|
688
|
+
href="{{ asset('assets/vendor/gaugeit/gaugeit.min.css') }}"
|
|
689
|
+
>
|
|
690
|
+
@endpush
|
|
691
|
+
|
|
692
|
+
<section>
|
|
693
|
+
<h2>Prediction accuracy</h2>
|
|
694
|
+
|
|
695
|
+
<div
|
|
696
|
+
id="accuracy-gauge"
|
|
697
|
+
data-options='@json([
|
|
698
|
+
"type" => "arc",
|
|
699
|
+
"min" => 0,
|
|
700
|
+
"max" => 100,
|
|
701
|
+
"value" => $accuracy,
|
|
702
|
+
"readout" => [
|
|
703
|
+
"value" => [
|
|
704
|
+
"visible" => true,
|
|
705
|
+
"suffix" => "%"
|
|
706
|
+
]
|
|
707
|
+
],
|
|
708
|
+
"accessibility" => [
|
|
709
|
+
"label" => "Prediction accuracy"
|
|
710
|
+
]
|
|
711
|
+
])'
|
|
712
|
+
></div>
|
|
713
|
+
</section>
|
|
714
|
+
|
|
715
|
+
@push('scripts')
|
|
716
|
+
<script src="{{ asset('assets/vendor/gaugeit/gaugeit.umd.min.js') }}"></script>
|
|
717
|
+
<script>
|
|
718
|
+
document.addEventListener('DOMContentLoaded', () => {
|
|
719
|
+
const host = document.querySelector('#accuracy-gauge');
|
|
720
|
+
if (!host) return;
|
|
721
|
+
|
|
722
|
+
const options = JSON.parse(host.dataset.options);
|
|
723
|
+
Gaugeit.createGauge(host, options);
|
|
724
|
+
});
|
|
725
|
+
</script>
|
|
726
|
+
@endpush
|
|
727
|
+
```
|
|
728
|
+
|
|
729
|
+
The package is a browser-asset distribution. PHP does not render the SVG server-side.
|
|
730
|
+
|
|
731
|
+
## 14. Custom element
|
|
732
|
+
|
|
733
|
+
```html
|
|
734
|
+
<!doctype html>
|
|
735
|
+
<html lang="en">
|
|
736
|
+
<head>
|
|
737
|
+
<meta charset="utf-8">
|
|
738
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
739
|
+
<title>Gaugeit.js custom element</title>
|
|
740
|
+
<link rel="stylesheet" href="./dist/gaugeit.min.css">
|
|
741
|
+
</head>
|
|
742
|
+
<body>
|
|
743
|
+
<gauge-it
|
|
744
|
+
id="voltage"
|
|
745
|
+
type="classic"
|
|
746
|
+
min="0"
|
|
747
|
+
max="240"
|
|
748
|
+
value="88"
|
|
749
|
+
options='{"readout":{"title":{"visible":true,"text":"VOLTAGE"},"unit":{"visible":true,"text":"V"}},"accessibility":{"label":"Voltage"}}'
|
|
750
|
+
></gauge-it>
|
|
751
|
+
|
|
752
|
+
<button id="increase" type="button">Increase</button>
|
|
753
|
+
|
|
754
|
+
<script src="./dist/gaugeit.umd.min.js"></script>
|
|
755
|
+
<script>
|
|
756
|
+
Gaugeit.defineGaugeitElement();
|
|
757
|
+
|
|
758
|
+
const element = document.querySelector('#voltage');
|
|
759
|
+
|
|
760
|
+
document.querySelector('#increase').addEventListener('click', () => {
|
|
761
|
+
element.value = Number(element.value) + 10;
|
|
762
|
+
});
|
|
763
|
+
</script>
|
|
764
|
+
</body>
|
|
765
|
+
</html>
|
|
766
|
+
```
|
|
767
|
+
|
|
768
|
+
Define the element before relying on its upgraded behavior. The `options` attribute
|
|
769
|
+
must contain valid JSON.
|
|
770
|
+
|
|
771
|
+
## 15. Data-attribute auto mounting
|
|
772
|
+
|
|
773
|
+
```html
|
|
774
|
+
<!doctype html>
|
|
775
|
+
<html lang="en">
|
|
776
|
+
<head>
|
|
777
|
+
<meta charset="utf-8">
|
|
778
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
779
|
+
<title>Gaugeit.js auto mounting</title>
|
|
780
|
+
<link rel="stylesheet" href="./dist/gaugeit.min.css">
|
|
781
|
+
</head>
|
|
782
|
+
<body>
|
|
783
|
+
<div
|
|
784
|
+
data-gaugeit
|
|
785
|
+
data-gaugeit-type="arc"
|
|
786
|
+
data-gaugeit-min="0"
|
|
787
|
+
data-gaugeit-max="100"
|
|
788
|
+
data-gaugeit-value="63"
|
|
789
|
+
data-gaugeit-options='{"readout":{"value":{"visible":true,"suffix":"%"}},"accessibility":{"label":"Completion"}}'
|
|
790
|
+
></div>
|
|
791
|
+
|
|
792
|
+
<script src="./dist/gaugeit.umd.min.js"></script>
|
|
793
|
+
<script>
|
|
794
|
+
const instances = Gaugeit.autoMount();
|
|
795
|
+
|
|
796
|
+
const first = instances[0];
|
|
797
|
+
first?.setValue(78);
|
|
798
|
+
</script>
|
|
799
|
+
</body>
|
|
800
|
+
</html>
|
|
801
|
+
```
|
|
802
|
+
|
|
803
|
+
Repeated `autoMount()` calls return existing managed instances instead of duplicating
|
|
804
|
+
them.
|
|
805
|
+
|
|
806
|
+
## 16. Custom gauge type from built-in layers
|
|
807
|
+
|
|
808
|
+
```html
|
|
809
|
+
<!doctype html>
|
|
810
|
+
<html lang="en">
|
|
811
|
+
<head>
|
|
812
|
+
<meta charset="utf-8">
|
|
813
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
814
|
+
<title>Custom Gaugeit.js type</title>
|
|
815
|
+
<link rel="stylesheet" href="./dist/gaugeit.min.css">
|
|
816
|
+
</head>
|
|
817
|
+
<body>
|
|
818
|
+
<div id="form-gauge"></div>
|
|
819
|
+
|
|
820
|
+
<script src="./dist/gaugeit.umd.min.js"></script>
|
|
821
|
+
<script>
|
|
822
|
+
Gaugeit.registerGaugeType('football-form', {
|
|
823
|
+
description: 'Compact recent-form performance instrument.',
|
|
824
|
+
|
|
825
|
+
defaults: {
|
|
826
|
+
min: 0,
|
|
827
|
+
max: 100,
|
|
828
|
+
|
|
829
|
+
geometry: {
|
|
830
|
+
width: 280,
|
|
831
|
+
height: 170,
|
|
832
|
+
centerX: 140,
|
|
833
|
+
centerY: 148,
|
|
834
|
+
radius: 104,
|
|
835
|
+
startAngle: 200,
|
|
836
|
+
endAngle: 340
|
|
837
|
+
},
|
|
838
|
+
|
|
839
|
+
track: {
|
|
840
|
+
radius: 96,
|
|
841
|
+
width: 22
|
|
842
|
+
},
|
|
843
|
+
|
|
844
|
+
scale: {
|
|
845
|
+
radius: 96
|
|
846
|
+
},
|
|
847
|
+
|
|
848
|
+
labels: {
|
|
849
|
+
radius: 72
|
|
850
|
+
},
|
|
851
|
+
|
|
852
|
+
pointer: {
|
|
853
|
+
type: 'arrow',
|
|
854
|
+
length: 82,
|
|
855
|
+
width: 6,
|
|
856
|
+
color: '#0f172a'
|
|
857
|
+
},
|
|
858
|
+
|
|
859
|
+
readout: {
|
|
860
|
+
title: {
|
|
861
|
+
visible: true,
|
|
862
|
+
text: 'FORM'
|
|
863
|
+
},
|
|
864
|
+
value: {
|
|
865
|
+
visible: true,
|
|
866
|
+
suffix: '%'
|
|
867
|
+
}
|
|
868
|
+
}
|
|
869
|
+
},
|
|
870
|
+
|
|
871
|
+
layers: [
|
|
872
|
+
Gaugeit.layers.face,
|
|
873
|
+
Gaugeit.layers.zones,
|
|
874
|
+
Gaugeit.layers.ticks,
|
|
875
|
+
Gaugeit.layers.labels,
|
|
876
|
+
Gaugeit.layers.light,
|
|
877
|
+
Gaugeit.layers.readout,
|
|
878
|
+
Gaugeit.layers.pointer
|
|
879
|
+
]
|
|
880
|
+
});
|
|
881
|
+
|
|
882
|
+
Gaugeit.createGauge('#form-gauge', {
|
|
883
|
+
type: 'football-form',
|
|
884
|
+
value: 74,
|
|
885
|
+
zones: [
|
|
886
|
+
{ min: 0, max: 40, color: '#ef4444' },
|
|
887
|
+
{ min: 40, max: 70, color: '#facc15' },
|
|
888
|
+
{ min: 70, max: 100, color: '#22c55e' }
|
|
889
|
+
],
|
|
890
|
+
accessibility: {
|
|
891
|
+
label: 'Recent form'
|
|
892
|
+
}
|
|
893
|
+
});
|
|
894
|
+
</script>
|
|
895
|
+
</body>
|
|
896
|
+
</html>
|
|
897
|
+
```
|
|
898
|
+
|
|
899
|
+
The pointer is placed after the readout in the layer array, so it paints above text.
|
|
900
|
+
|
|
901
|
+
## 17. Custom dynamic layer
|
|
902
|
+
|
|
903
|
+
```js
|
|
904
|
+
const targetMarkerLayer = {
|
|
905
|
+
id: 'target-marker',
|
|
906
|
+
|
|
907
|
+
render({ options, renderer }) {
|
|
908
|
+
const group = renderer.group('target-marker', {
|
|
909
|
+
'aria-hidden': 'true'
|
|
910
|
+
});
|
|
911
|
+
|
|
912
|
+
const marker = document.createElementNS(
|
|
913
|
+
'http://www.w3.org/2000/svg',
|
|
914
|
+
'circle'
|
|
915
|
+
);
|
|
916
|
+
|
|
917
|
+
marker.setAttribute('r', String(options.targetMarker.radius));
|
|
918
|
+
marker.setAttribute('fill', options.targetMarker.color);
|
|
919
|
+
group.append(marker);
|
|
920
|
+
|
|
921
|
+
return {
|
|
922
|
+
update(value) {
|
|
923
|
+
const point = Gaugeit.geometry.polarPoint(
|
|
924
|
+
options.geometry.centerX,
|
|
925
|
+
options.geometry.centerY,
|
|
926
|
+
options.targetMarker.distance,
|
|
927
|
+
Gaugeit.geometry.valueToAngle(value, options)
|
|
928
|
+
);
|
|
929
|
+
|
|
930
|
+
marker.setAttribute('cx', String(point.x));
|
|
931
|
+
marker.setAttribute('cy', String(point.y));
|
|
932
|
+
}
|
|
933
|
+
};
|
|
934
|
+
}
|
|
935
|
+
};
|
|
936
|
+
|
|
937
|
+
Gaugeit.registerGaugeType('target-marker-gauge', {
|
|
938
|
+
defaults: {
|
|
939
|
+
targetMarker: {
|
|
940
|
+
radius: 4,
|
|
941
|
+
distance: 102,
|
|
942
|
+
color: '#2563eb'
|
|
943
|
+
}
|
|
944
|
+
},
|
|
945
|
+
|
|
946
|
+
layers: [
|
|
947
|
+
Gaugeit.layers.face,
|
|
948
|
+
Gaugeit.layers.zones,
|
|
949
|
+
Gaugeit.layers.ticks,
|
|
950
|
+
Gaugeit.layers.labels,
|
|
951
|
+
targetMarkerLayer,
|
|
952
|
+
Gaugeit.layers.readout,
|
|
953
|
+
Gaugeit.layers.pointer
|
|
954
|
+
]
|
|
955
|
+
});
|
|
956
|
+
```
|
|
957
|
+
|
|
958
|
+
Use controller `value` for stable animated display semantics. Use
|
|
959
|
+
`state.pointerValue` only if the custom artwork should include jitter.
|
|
960
|
+
|
|
961
|
+
## 18. Destroy and recreate safely
|
|
962
|
+
|
|
963
|
+
```html
|
|
964
|
+
<!doctype html>
|
|
965
|
+
<html lang="en">
|
|
966
|
+
<head>
|
|
967
|
+
<meta charset="utf-8">
|
|
968
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
969
|
+
<title>Gaugeit.js lifecycle</title>
|
|
970
|
+
<link rel="stylesheet" href="./dist/gaugeit.min.css">
|
|
971
|
+
</head>
|
|
972
|
+
<body>
|
|
973
|
+
<div id="gauge"></div>
|
|
974
|
+
<button id="recreate" type="button">Recreate</button>
|
|
975
|
+
<button id="destroy" type="button">Destroy</button>
|
|
976
|
+
|
|
977
|
+
<script src="./dist/gaugeit.umd.min.js"></script>
|
|
978
|
+
<script>
|
|
979
|
+
const host = document.querySelector('#gauge');
|
|
980
|
+
let gauge = create();
|
|
981
|
+
|
|
982
|
+
function create() {
|
|
983
|
+
return Gaugeit.createGauge(host, {
|
|
984
|
+
type: 'arc',
|
|
985
|
+
min: 0,
|
|
986
|
+
max: 100,
|
|
987
|
+
value: 50,
|
|
988
|
+
accessibility: {
|
|
989
|
+
label: 'Lifecycle demonstration'
|
|
990
|
+
}
|
|
991
|
+
});
|
|
992
|
+
}
|
|
993
|
+
|
|
994
|
+
document.querySelector('#recreate').addEventListener('click', () => {
|
|
995
|
+
gauge.destroy();
|
|
996
|
+
gauge = create();
|
|
997
|
+
});
|
|
998
|
+
|
|
999
|
+
document.querySelector('#destroy').addEventListener('click', () => {
|
|
1000
|
+
gauge.destroy();
|
|
1001
|
+
});
|
|
1002
|
+
</script>
|
|
1003
|
+
</body>
|
|
1004
|
+
</html>
|
|
1005
|
+
```
|
|
1006
|
+
|
|
1007
|
+
`createGauge()` is managed and already destroys an existing managed gauge on the same
|
|
1008
|
+
host. Explicit destruction is shown because it makes ownership clear and is required
|
|
1009
|
+
when the application is removing the component permanently.
|
|
1010
|
+
|
|
1011
|
+
## 19. Listen for value and animation completion
|
|
1012
|
+
|
|
1013
|
+
```js
|
|
1014
|
+
const host = document.querySelector('#gauge');
|
|
1015
|
+
const gauge = Gaugeit.createGauge(host, {
|
|
1016
|
+
type: 'arc',
|
|
1017
|
+
value: 10
|
|
1018
|
+
});
|
|
1019
|
+
|
|
1020
|
+
host.addEventListener('gaugeit:change', (event) => {
|
|
1021
|
+
console.log('Requested value:', event.detail.value);
|
|
1022
|
+
});
|
|
1023
|
+
|
|
1024
|
+
host.addEventListener('gaugeit:displaychange', (event) => {
|
|
1025
|
+
console.log('Displayed value:', event.detail.displayedValue);
|
|
1026
|
+
});
|
|
1027
|
+
|
|
1028
|
+
host.addEventListener('gaugeit:settled', (event) => {
|
|
1029
|
+
console.log('Animation settled:', event.detail.displayedValue);
|
|
1030
|
+
});
|
|
1031
|
+
|
|
1032
|
+
gauge.setValue(90);
|
|
1033
|
+
```
|
|
1034
|
+
|
|
1035
|
+
Use host-scoped namespaced events. Do not install an unscoped global callback API.
|
|
1036
|
+
|
|
1037
|
+
## 20. Switch complete configurations
|
|
1038
|
+
|
|
1039
|
+
Use `replaceOptions()` when switching instrument modes:
|
|
1040
|
+
|
|
1041
|
+
```js
|
|
1042
|
+
const gauge = Gaugeit.createGauge('#instrument', {
|
|
1043
|
+
type: 'arc',
|
|
1044
|
+
min: 0,
|
|
1045
|
+
max: 100,
|
|
1046
|
+
value: 40
|
|
1047
|
+
});
|
|
1048
|
+
|
|
1049
|
+
function showTemperature(value) {
|
|
1050
|
+
gauge.replaceOptions({
|
|
1051
|
+
type: 'classic',
|
|
1052
|
+
min: -20,
|
|
1053
|
+
max: 120,
|
|
1054
|
+
value,
|
|
1055
|
+
readout: {
|
|
1056
|
+
title: {
|
|
1057
|
+
visible: true,
|
|
1058
|
+
text: 'TEMPERATURE'
|
|
1059
|
+
},
|
|
1060
|
+
value: {
|
|
1061
|
+
visible: true
|
|
1062
|
+
},
|
|
1063
|
+
unit: {
|
|
1064
|
+
visible: true,
|
|
1065
|
+
text: '°C'
|
|
1066
|
+
}
|
|
1067
|
+
},
|
|
1068
|
+
accessibility: {
|
|
1069
|
+
label: 'Temperature'
|
|
1070
|
+
}
|
|
1071
|
+
});
|
|
1072
|
+
}
|
|
1073
|
+
|
|
1074
|
+
function showBalance(value) {
|
|
1075
|
+
gauge.replaceOptions({
|
|
1076
|
+
type: 'center-zero',
|
|
1077
|
+
min: -100,
|
|
1078
|
+
max: 100,
|
|
1079
|
+
value,
|
|
1080
|
+
readout: {
|
|
1081
|
+
title: {
|
|
1082
|
+
visible: true,
|
|
1083
|
+
text: 'BALANCE'
|
|
1084
|
+
},
|
|
1085
|
+
value: {
|
|
1086
|
+
visible: true
|
|
1087
|
+
}
|
|
1088
|
+
},
|
|
1089
|
+
accessibility: {
|
|
1090
|
+
label: 'Balance'
|
|
1091
|
+
}
|
|
1092
|
+
});
|
|
1093
|
+
}
|
|
1094
|
+
```
|
|
1095
|
+
|
|
1096
|
+
`updateOptions()` would retain earlier overrides that are omitted from the new mode.
|
|
1097
|
+
`replaceOptions()` resets omitted keys to the new type defaults.
|
|
1098
|
+
|
|
1099
|
+
## Recipe verification checklist
|
|
1100
|
+
|
|
1101
|
+
Before returning generated integration code, verify:
|
|
1102
|
+
|
|
1103
|
+
- JavaScript distribution matches the environment.
|
|
1104
|
+
- CSS is loaded unless standalone is used.
|
|
1105
|
+
- The global is `Gaugeit`.
|
|
1106
|
+
- Package import paths use lowercase `gaugeit.js`.
|
|
1107
|
+
- The React component is `Gaugeit`.
|
|
1108
|
+
- The target exists before creation.
|
|
1109
|
+
- The selected built-in type name is exact.
|
|
1110
|
+
- Center-zero range contains its zero reference.
|
|
1111
|
+
- Readout child visibility is explicit.
|
|
1112
|
+
- Manual lights use `trigger.mode: 'manual'`.
|
|
1113
|
+
- Blink/pulse precedence is intentional.
|
|
1114
|
+
- Application timers and listeners have cleanup.
|
|
1115
|
+
- Component unmount destroys an owned instance.
|
|
1116
|
+
- CDN URLs pin `0.1.1`.
|
|
1117
|
+
- Accessibility label and value text are meaningful.
|