@fundar/data-chart-telling 0.0.38 → 0.0.40
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/plots/bar/Plot.svelte +275 -249
- package/dist/plots/line/Plot.svelte +207 -182
- package/dist/plots/pyramid/Plot.svelte +288 -260
- package/dist/plots/scatter/Plot.svelte +266 -242
- package/dist/plots/utils/labelOverflow.svelte.d.ts +17 -1
- package/dist/plots/utils/labelOverflow.svelte.js +57 -11
- package/package.json +1 -1
|
@@ -37,12 +37,21 @@ export function watchLabelOverflow(args) {
|
|
|
37
37
|
catch {
|
|
38
38
|
return;
|
|
39
39
|
}
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
40
|
+
// An empty group (no labels currently rendered, e.g. every series is
|
|
41
|
+
// scrubbed/filtered out of view) reports getBBox() as (0,0,0,0) — the
|
|
42
|
+
// SVG origin, not "no content". Reading that literally as a box sitting
|
|
43
|
+
// at (0,0) would report overflow proportional to the *current* margins
|
|
44
|
+
// themselves, which grows them, which remounts this group against the
|
|
45
|
+
// new, larger bounds, which reports overflow again — an unbounded loop
|
|
46
|
+
// with nothing rendered to justify it.
|
|
47
|
+
const overflow = box.width === 0 && box.height === 0
|
|
48
|
+
? NO_OVERFLOW
|
|
49
|
+
: {
|
|
50
|
+
left: Math.ceil(Math.max(0, bounds.left - box.x)),
|
|
51
|
+
right: Math.ceil(Math.max(0, box.x + box.width - bounds.right)),
|
|
52
|
+
top: Math.ceil(Math.max(0, bounds.top - box.y)),
|
|
53
|
+
bottom: Math.ceil(Math.max(0, box.y + box.height - bounds.bottom))
|
|
54
|
+
};
|
|
46
55
|
attempt += 1;
|
|
47
56
|
const stable = lastReading != null &&
|
|
48
57
|
lastReading.left === overflow.left &&
|
|
@@ -78,15 +87,48 @@ export function watchLabelOverflow(args) {
|
|
|
78
87
|
* "shrink margin → overflow reappears → grow margin → …". Each side is only
|
|
79
88
|
* ever set when the caller's own `margins` prop hasn't already pinned it, so
|
|
80
89
|
* an explicit caller override always wins over this auto-grown one.
|
|
90
|
+
*
|
|
91
|
+
* That monotonic growth is only sound for a *stable* dataset — it assumes
|
|
92
|
+
* every reading describes the same thing being measured, just possibly at an
|
|
93
|
+
* earlier, not-yet-settled frame. It stops being sound once the caller's own
|
|
94
|
+
* data changes identity underneath it (e.g. a timeline scrubber revealing a
|
|
95
|
+
* different slice of rows on every tick): an overflow measured against
|
|
96
|
+
* *that* frame's rendered labels doesn't describe the next frame's, so
|
|
97
|
+
* carrying it forward forever can leave a plot permanently — and wrongly —
|
|
98
|
+
* margin-inflated by whatever the single most cluttered frame it ever
|
|
99
|
+
* passed through needed, long after scrubbing away from it. `resetKey`, if
|
|
100
|
+
* given, is compared by identity on every call; a change drops `measured`
|
|
101
|
+
* back to zero so the next frame's overflow is measured fresh against only
|
|
102
|
+
* what's actually on screen now. Pass whatever reactive value identifies
|
|
103
|
+
* "what's currently being plotted" for the caller (e.g. its own resolved
|
|
104
|
+
* series list) — a plain reference/value comparison, not a deep one, so it
|
|
105
|
+
* only need change identity when the rendered content actually does.
|
|
81
106
|
*/
|
|
82
|
-
export function createLabelMarginTracker(margins) {
|
|
107
|
+
export function createLabelMarginTracker(margins, resetKey) {
|
|
83
108
|
let measured = $state(NO_OVERFLOW);
|
|
109
|
+
// Skips the reset on the very first run (there's nothing to reset yet,
|
|
110
|
+
// and `measured` already starts at `NO_OVERFLOW`) so only a later,
|
|
111
|
+
// genuine change to `resetKey` clears accumulated growth.
|
|
112
|
+
let resetKeyInitialized = false;
|
|
113
|
+
let lastResetKey;
|
|
114
|
+
$effect(() => {
|
|
115
|
+
const key = resetKey?.();
|
|
116
|
+
if (!resetKeyInitialized) {
|
|
117
|
+
resetKeyInitialized = true;
|
|
118
|
+
lastResetKey = key;
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
if (key !== lastResetKey) {
|
|
122
|
+
lastResetKey = key;
|
|
123
|
+
measured = NO_OVERFLOW;
|
|
124
|
+
}
|
|
125
|
+
});
|
|
84
126
|
function report(overflow) {
|
|
85
127
|
const next = {
|
|
86
128
|
left: Math.max(measured.left, overflow.left),
|
|
87
129
|
right: Math.max(measured.right, overflow.right),
|
|
88
130
|
top: Math.max(measured.top, overflow.top),
|
|
89
|
-
bottom: Math.max(measured.bottom, overflow.bottom)
|
|
131
|
+
bottom: Math.max(measured.bottom, overflow.bottom)
|
|
90
132
|
};
|
|
91
133
|
if (next.left !== measured.left ||
|
|
92
134
|
next.right !== measured.right ||
|
|
@@ -126,11 +168,15 @@ export function createLabelMarginTracker(margins) {
|
|
|
126
168
|
// must track.
|
|
127
169
|
const plotProps = $derived.by(() => ({
|
|
128
170
|
margins: resolvedMargins,
|
|
129
|
-
marginRemountKey: JSON.stringify(measured)
|
|
171
|
+
marginRemountKey: JSON.stringify(measured)
|
|
130
172
|
}));
|
|
131
173
|
return {
|
|
132
174
|
report,
|
|
133
|
-
get resolvedMargins() {
|
|
134
|
-
|
|
175
|
+
get resolvedMargins() {
|
|
176
|
+
return resolvedMargins;
|
|
177
|
+
},
|
|
178
|
+
get plotProps() {
|
|
179
|
+
return plotProps;
|
|
180
|
+
}
|
|
135
181
|
};
|
|
136
182
|
}
|