@design.estate/dees-catalog 3.98.0 → 3.99.0
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/dist_bundle/bundle.js +476 -118
- package/dist_ts_web/00_commitinfo_data.js +1 -1
- package/dist_ts_web/elements/00group-chart/dees-chart-area/component.d.ts +36 -0
- package/dist_ts_web/elements/00group-chart/dees-chart-area/component.js +444 -118
- package/dist_ts_web/elements/00group-chart/dees-chart-area/realtime-updates.d.ts +21 -0
- package/dist_ts_web/elements/00group-chart/dees-chart-area/realtime-updates.js +79 -0
- package/dist_ts_web/elements/00group-chart/dees-chart-area/styles.js +11 -1
- package/dist_ts_web/elements/00group-chart/dees-chart-area/template.js +4 -2
- package/package.json +2 -2
- package/readme.md +10 -1
- package/ts_web/00_commitinfo_data.ts +1 -1
- package/ts_web/elements/00group-chart/dees-chart-area/component.ts +438 -115
- package/ts_web/elements/00group-chart/dees-chart-area/realtime-updates.ts +110 -0
- package/ts_web/elements/00group-chart/dees-chart-area/styles.ts +10 -0
- package/ts_web/elements/00group-chart/dees-chart-area/template.ts +3 -1
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
export interface IRealtimeChartPoint {
|
|
2
|
+
time: number;
|
|
3
|
+
value: number;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
export interface IRealtimeChartUpdate {
|
|
7
|
+
point: IRealtimeChartPoint;
|
|
8
|
+
historicalUpdate: boolean;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export interface IRealtimeChartUpdatePlan {
|
|
12
|
+
replacementRequired: boolean;
|
|
13
|
+
updates: IRealtimeChartUpdate[];
|
|
14
|
+
pruneRecommended: boolean;
|
|
15
|
+
pruneRequired: boolean;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Lightweight Charts can update the newest point or append newer points with
|
|
20
|
+
* update(). Historical update() calls may only target timestamps that already
|
|
21
|
+
* exist. Everything else needs an exact setData() replacement.
|
|
22
|
+
*/
|
|
23
|
+
export const planRealtimeChartUpdates = (
|
|
24
|
+
renderedData: readonly IRealtimeChartPoint[],
|
|
25
|
+
canonicalData: readonly IRealtimeChartPoint[],
|
|
26
|
+
): IRealtimeChartUpdatePlan => {
|
|
27
|
+
if (canonicalData.length === 0) {
|
|
28
|
+
return {
|
|
29
|
+
replacementRequired: renderedData.length !== 0,
|
|
30
|
+
updates: [],
|
|
31
|
+
pruneRecommended: false,
|
|
32
|
+
pruneRequired: false,
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
if (renderedData.length === 0) {
|
|
36
|
+
return {
|
|
37
|
+
replacementRequired: false,
|
|
38
|
+
updates: canonicalData.map((point) => ({ point, historicalUpdate: false })),
|
|
39
|
+
pruneRecommended: false,
|
|
40
|
+
pruneRequired: false,
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const renderedByTime = new Map(renderedData.map((point) => [point.time, point]));
|
|
45
|
+
const canonicalByTime = new Map(canonicalData.map((point) => [point.time, point]));
|
|
46
|
+
const canonicalStart = canonicalData[0].time;
|
|
47
|
+
const renderedLastTime = renderedData[renderedData.length - 1].time;
|
|
48
|
+
|
|
49
|
+
// Points before canonicalStart are an expired rolling-window prefix and may
|
|
50
|
+
// stay hidden temporarily. Missing points anywhere else are structural
|
|
51
|
+
// deletions (including suffix deletion) and require an exact replacement.
|
|
52
|
+
const hasStructuralDeletion = renderedData.some(
|
|
53
|
+
(point) => point.time >= canonicalStart && !canonicalByTime.has(point.time),
|
|
54
|
+
);
|
|
55
|
+
if (hasStructuralDeletion) {
|
|
56
|
+
return {
|
|
57
|
+
replacementRequired: true,
|
|
58
|
+
updates: [],
|
|
59
|
+
pruneRecommended: false,
|
|
60
|
+
pruneRequired: false,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const updates: IRealtimeChartUpdate[] = [];
|
|
65
|
+
for (const canonicalPoint of canonicalData) {
|
|
66
|
+
const renderedPoint = renderedByTime.get(canonicalPoint.time);
|
|
67
|
+
if (!renderedPoint) {
|
|
68
|
+
if (canonicalPoint.time < renderedLastTime) {
|
|
69
|
+
// Historical update() cannot insert a missing timestamp.
|
|
70
|
+
return {
|
|
71
|
+
replacementRequired: true,
|
|
72
|
+
updates: [],
|
|
73
|
+
pruneRecommended: false,
|
|
74
|
+
pruneRequired: false,
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
updates.push({ point: canonicalPoint, historicalUpdate: false });
|
|
78
|
+
continue;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
if (renderedPoint.value !== canonicalPoint.value) {
|
|
82
|
+
updates.push({
|
|
83
|
+
point: canonicalPoint,
|
|
84
|
+
historicalUpdate: canonicalPoint.time < renderedLastTime,
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const firstCanonicalPointIndex = renderedData.findIndex((point) => point.time >= canonicalStart);
|
|
90
|
+
const retainedPrefixLength = firstCanonicalPointIndex === -1
|
|
91
|
+
? renderedData.length
|
|
92
|
+
: firstCanonicalPointIndex;
|
|
93
|
+
const projectedLength = renderedData.length
|
|
94
|
+
+ updates.filter((update) => !renderedByTime.has(update.point.time)).length;
|
|
95
|
+
// Retain at most one additional hidden rolling window before compacting.
|
|
96
|
+
const retentionLimit = Math.max(canonicalData.length * 2, 2);
|
|
97
|
+
const pruneRecommended = retainedPrefixLength > 0 && projectedLength > retentionLimit;
|
|
98
|
+
// Hover may defer a recommended compaction to preserve the active crosshair,
|
|
99
|
+
// but never beyond two additional hidden windows.
|
|
100
|
+
const hardRetentionLimit = Math.max(canonicalData.length * 3, 3);
|
|
101
|
+
const pruneRequired = retainedPrefixLength > 0 && projectedLength > hardRetentionLimit;
|
|
102
|
+
|
|
103
|
+
return { replacementRequired: false, updates, pruneRecommended, pruneRequired };
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
export const haveSameSeriesLayout = (
|
|
107
|
+
renderedNames: readonly string[],
|
|
108
|
+
canonicalNames: readonly string[],
|
|
109
|
+
): boolean => renderedNames.length === canonicalNames.length
|
|
110
|
+
&& renderedNames.every((name, index) => name === canonicalNames[index]);
|
|
@@ -50,6 +50,16 @@ export const chartAreaStyles = [
|
|
|
50
50
|
position: absolute;
|
|
51
51
|
inset: 0 0 4px 0;
|
|
52
52
|
}
|
|
53
|
+
.rangeSelectionOverlay {
|
|
54
|
+
position: absolute;
|
|
55
|
+
display: none;
|
|
56
|
+
top: 0;
|
|
57
|
+
bottom: 0;
|
|
58
|
+
z-index: 3;
|
|
59
|
+
pointer-events: none;
|
|
60
|
+
background: color-mix(in srgb, var(--dees-color-accent, #3b82f6) 18%, transparent);
|
|
61
|
+
border-inline: 1px solid color-mix(in srgb, var(--dees-color-accent, #3b82f6) 70%, transparent);
|
|
62
|
+
}
|
|
53
63
|
.statsBar {
|
|
54
64
|
min-height: 32px;
|
|
55
65
|
padding: 4px 16px;
|
|
@@ -11,7 +11,9 @@ export const renderChartArea = (component: DeesChartArea): TemplateResult => {
|
|
|
11
11
|
<dees-icon .icon=${component.isFullPage ? 'lucide:Minimize2' : 'lucide:Maximize2'} .iconSize=${14}></dees-icon>
|
|
12
12
|
</button>
|
|
13
13
|
</div>
|
|
14
|
-
<div class="chartContainer"
|
|
14
|
+
<div class="chartContainer">
|
|
15
|
+
<div class="rangeSelectionOverlay" aria-hidden="true"></div>
|
|
16
|
+
</div>
|
|
15
17
|
${component.seriesStats.length > 0 && !component.hideLegend ? html`
|
|
16
18
|
<div slot="footer" class="statsBar">
|
|
17
19
|
${component.seriesStats.map(s => html`
|