@bicharts/chart-host 0.6.88 → 0.6.90
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 +49 -0
- package/dist/adapters.mjs +3 -3
- package/dist/{chunk-YDHXOIAI.mjs → chunk-45VILLJT.mjs} +2 -0
- package/dist/{chunk-56IZWXW2.mjs → chunk-CR7DSJVG.mjs} +1 -1
- package/dist/{chunk-HXH6NIRV.mjs → chunk-FHHT7DBM.mjs} +247 -6
- package/dist/{chunk-QHIPRAZK.mjs → chunk-NNLBFIWU.mjs} +51 -2
- package/dist/{chunk-XNS34AMM.mjs → chunk-PDVEIW42.mjs} +1 -1
- package/dist/{chunk-IZXVV74H.mjs → chunk-QHMLMF4L.mjs} +2 -2
- package/dist/{chunk-UBB5LNH4.mjs → chunk-VC3Z5CH7.mjs} +1 -1
- package/dist/{chunk-IUXNCX7D.mjs → chunk-VEVBXK44.mjs} +8 -2
- package/dist/index.mjs +15 -7
- package/dist/legend-fit.mjs +3 -3
- package/dist/page.mjs +4 -4
- package/dist/react.mjs +15 -9
- package/dist/testing.mjs +1 -1
- package/dist/types/contract.d.ts +5 -0
- package/dist/types/fit.d.ts +23 -0
- package/dist/types/fitDom.d.ts +24 -1
- package/dist/types/host.d.ts +24 -0
- package/dist/types/index.d.ts +3 -1
- package/dist/types/react.d.ts +9 -0
- package/dist/types/selection.d.ts +12 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -277,6 +277,41 @@ stylesheet's `0.25`, or whatever your page sets on the variable.
|
|
|
277
277
|
createChartHost(el, { code, data, options: { dimOpacity: 0.15 } });
|
|
278
278
|
```
|
|
279
279
|
|
|
280
|
+
**A glyph on each selected mark.** `options.selectionGlyph` (`"dot"` or `"check"`; absent or
|
|
281
|
+
`"none"` draws nothing, the default) puts a small glyph on every selected mark, in a layer the host
|
|
282
|
+
owns inside the container (`.bic-selection-glyphs`, each glyph `.lch-sel-glyph`, never hit-tested).
|
|
283
|
+
It is painted after every selection change and, on a redraw, after the layout pass and the fit, so
|
|
284
|
+
nothing measures it as part of the chart. Only a mark the reader can see gets one: a mark hidden by
|
|
285
|
+
`visibility` or `opacity` (a legend toggle) and a mark outside its svg's frame or its plot's
|
|
286
|
+
`clip-path` (a point panned into the axis margin) get none. While a selection is lit, a mark that
|
|
287
|
+
moves or hides without a redraw (a pan or zoom, a transition, an animation frame, a legend toggle)
|
|
288
|
+
takes its glyph with it on the next frame; a write that holds no mark (a hover dot, a tooltip)
|
|
289
|
+
repaints nothing, and that repaint is not reported again. Where the browser has a `ResizeObserver`,
|
|
290
|
+
a container resized without a redraw (a responsive chart, a hidden tab shown) is repainted too, and
|
|
291
|
+
reported when it drew a different count. The layer clips at the container's scroll area, so a
|
|
292
|
+
glyph never widens what the container scrolls, and it sits under the note badges, under a chart's
|
|
293
|
+
own tooltip or control that sets a `z-index` above 1, and under a pinned axis, so a glyph on a row
|
|
294
|
+
scrolled beneath the axis is covered with its row. When the page left the container
|
|
295
|
+
`position: static`, the host makes it `relative` so the layer scrolls and clips with the marks, and
|
|
296
|
+
`destroy()` puts back what the page had. A period picked on a chart's own timeline dims nothing and
|
|
297
|
+
marks nothing.
|
|
298
|
+
|
|
299
|
+
Some charts never take a glyph: on a flow or relationship chart a selected series would get one on
|
|
300
|
+
every point. The generate answer says so (`suppressSelectionGlyph`, read by shape-core's
|
|
301
|
+
`parseGenerateResponse`); pass it as `options.suppressSelectionGlyph`, or leave it in the payload's
|
|
302
|
+
`meta` (`data.meta.suppressSelectionGlyph`) and the host promotes it, the way it promotes
|
|
303
|
+
`geoPoint`. Keep it with the chart's code, so a redraw from a cache honors it too.
|
|
304
|
+
`onSelectionGlyphs` reports what each paint did (`{ mode, drawn, total, suppressed }`), and is
|
|
305
|
+
called only when a glyph mode is set:
|
|
306
|
+
|
|
307
|
+
```js
|
|
308
|
+
createChartHost(el, {
|
|
309
|
+
code, data,
|
|
310
|
+
options: { selectionGlyph: "dot", suppressSelectionGlyph: answer.suppressSelectionGlyph },
|
|
311
|
+
onSelectionGlyphs: r => console.debug("glyphs", r),
|
|
312
|
+
});
|
|
313
|
+
```
|
|
314
|
+
|
|
280
315
|
**Which marks count as selected.** By default a mark is selected when *any* of the rows in its
|
|
281
316
|
`data-row-idx` list is selected, which is what lights a legend swatch together with its series. A
|
|
282
317
|
chart whose marks share rows declares the other rule by stamping
|
|
@@ -385,6 +420,20 @@ only while `rememberAcrossSessions()` is true. It is keyed by the chart's code a
|
|
|
385
420
|
somewhere arbitrary. A chart with several zoomable panels is left alone. In React, pass the hook as
|
|
386
421
|
the `zoomMemory` prop of `<BicChart>`.
|
|
387
422
|
|
|
423
|
+
**A scrolled chart** keeps its place with no setup. A chart taller than its frame scrolls, and every
|
|
424
|
+
redraw empties the container, which used to send the reader back to the top. The host now parks the
|
|
425
|
+
scroll offset on the container before it clears it, and the fit puts it back once the new layout has
|
|
426
|
+
decided whether it still scrolls. The offset is clamped to what the new layout can scroll, and only
|
|
427
|
+
restored on an axis that still scrolls. That covers a resize, a filter, a restyle, and a new host
|
|
428
|
+
created on the same element. The memory is keyed by the chart (its `code`, or the `renderFn`'s
|
|
429
|
+
source text), so a different chart opens at the top, while a `renderFn` closure rebuilt on every draw
|
|
430
|
+
is still the same chart. It lives on the element for the session
|
|
431
|
+
only, and nothing is persisted. A page that manages the container's scrolling itself passes
|
|
432
|
+
`restoreScroll: false` (the `restoreScroll` prop of `<BicChart>`), and then nothing is remembered or
|
|
433
|
+
restored. A host that clears and fits its container on its own can use the same pieces:
|
|
434
|
+
`rememberScroll` before the clear, `takeScroll` after the render, and `fitRenderedChart`'s
|
|
435
|
+
`restoreScroll` option (or the pure `planScrollRestore`).
|
|
436
|
+
|
|
388
437
|
## Keeping a drawn chart readable inside its frame
|
|
389
438
|
|
|
390
439
|
A generated chart cannot know how wide its own legend text will come out, where its tick labels will
|
package/dist/adapters.mjs
CHANGED
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
censusHitBands,
|
|
4
4
|
ensureCrossfilterHitTargets,
|
|
5
5
|
hitBandFlag
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-PDVEIW42.mjs";
|
|
7
7
|
import {
|
|
8
8
|
clickWasDrag,
|
|
9
9
|
collectD3GlyphCenters,
|
|
@@ -12,13 +12,13 @@ import {
|
|
|
12
12
|
markKeyOf,
|
|
13
13
|
rowIdxsFromMark,
|
|
14
14
|
selectionRuleOf
|
|
15
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-VEVBXK44.mjs";
|
|
16
16
|
import {
|
|
17
17
|
AXIS_FILTER_CLASS,
|
|
18
18
|
LEGEND_MARK_CLASS,
|
|
19
19
|
MARK_CLASS,
|
|
20
20
|
ROW_IDX_ATTR
|
|
21
|
-
} from "./chunk-
|
|
21
|
+
} from "./chunk-45VILLJT.mjs";
|
|
22
22
|
import "./chunk-GHODWOAL.mjs";
|
|
23
23
|
|
|
24
24
|
// src/adapters/types.ts
|
|
@@ -19,6 +19,7 @@ var CONTAINER_SLOT_ANIM_STOP = "__llmAnimStop";
|
|
|
19
19
|
var CONTAINER_SLOT_XF_CLEAR = "__llmXfClear";
|
|
20
20
|
var CONTAINER_SLOT_INITIAL_XF_MARK = "__llmInitialXfMark";
|
|
21
21
|
var CONTAINER_SLOT_UI_STATE = "__lchUiState";
|
|
22
|
+
var CONTAINER_SLOT_SCROLL = "__lchScroll";
|
|
22
23
|
var CONTAINER_SLOT_CLICKED_MARKS = "__lchClickedMarks";
|
|
23
24
|
var VIEW_ONLY_UI_STATE_KEYS = Object.freeze(["camera", "llmZoom"]);
|
|
24
25
|
function withoutViewOnlyKeys(bag) {
|
|
@@ -89,6 +90,7 @@ export {
|
|
|
89
90
|
CONTAINER_SLOT_XF_CLEAR,
|
|
90
91
|
CONTAINER_SLOT_INITIAL_XF_MARK,
|
|
91
92
|
CONTAINER_SLOT_UI_STATE,
|
|
93
|
+
CONTAINER_SLOT_SCROLL,
|
|
92
94
|
CONTAINER_SLOT_CLICKED_MARKS,
|
|
93
95
|
VIEW_ONLY_UI_STATE_KEYS,
|
|
94
96
|
withoutViewOnlyKeys,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/*! @bicharts/chart-host — Apache-2.0. Bundled reference data: GeoNames (https://www.geonames.org/) CC BY 4.0; Natural Earth and US Census/TIGER (public domain). Full text: NOTICE in this package. */
|
|
2
2
|
import {
|
|
3
3
|
LASSO_KNOB_KEY
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-QHMLMF4L.mjs";
|
|
5
5
|
|
|
6
6
|
// src/filterScope.ts
|
|
7
7
|
function viewToken(view) {
|
|
@@ -2,30 +2,35 @@
|
|
|
2
2
|
import {
|
|
3
3
|
LASSO_OUTLINE_CLASS,
|
|
4
4
|
installLasso
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-QHMLMF4L.mjs";
|
|
6
6
|
import {
|
|
7
7
|
censusHitBands,
|
|
8
8
|
ensureCrossfilterHitTargets
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-PDVEIW42.mjs";
|
|
10
10
|
import {
|
|
11
11
|
clearPress,
|
|
12
|
+
clearSelectionGlyphs,
|
|
12
13
|
clickWasDrag,
|
|
14
|
+
collectGlyphCentersWhere,
|
|
13
15
|
createMarkResolver,
|
|
14
16
|
isInsideControl,
|
|
15
17
|
markKeyOf,
|
|
16
18
|
nextClickedMarks,
|
|
17
19
|
nextSelection,
|
|
20
|
+
paintSelectionGlyphs,
|
|
18
21
|
planSelectionPaint,
|
|
19
22
|
sameRowSet,
|
|
20
23
|
selectionRuleOf,
|
|
21
24
|
trackPress,
|
|
22
25
|
validRowSet
|
|
23
|
-
} from "./chunk-
|
|
26
|
+
} from "./chunk-VEVBXK44.mjs";
|
|
24
27
|
import {
|
|
25
28
|
clipWindowOf,
|
|
26
29
|
fitRenderedChart,
|
|
30
|
+
rememberScroll,
|
|
31
|
+
takeScroll,
|
|
27
32
|
unpinScrolledAxis
|
|
28
|
-
} from "./chunk-
|
|
33
|
+
} from "./chunk-NNLBFIWU.mjs";
|
|
29
34
|
import {
|
|
30
35
|
Fn,
|
|
31
36
|
J3,
|
|
@@ -79,7 +84,7 @@ import {
|
|
|
79
84
|
XFILTER_REFRESH_EVENT,
|
|
80
85
|
chartOwnsTimeline,
|
|
81
86
|
periodTickSuppressesFeedback
|
|
82
|
-
} from "./chunk-
|
|
87
|
+
} from "./chunk-45VILLJT.mjs";
|
|
83
88
|
|
|
84
89
|
// src/labelContrast.ts
|
|
85
90
|
function parseRGBA(c) {
|
|
@@ -615,6 +620,14 @@ function resolveOptions(p) {
|
|
|
615
620
|
const n = numberOr(p.dimOpacity, NaN);
|
|
616
621
|
return Number.isFinite(n) ? clamp(n, DIM_OPACITY_MIN, 1) : void 0;
|
|
617
622
|
})(),
|
|
623
|
+
// A recognised glyph or none: an unknown string must never reach the painter as a live mode, and "none" is
|
|
624
|
+
// undefined rather than a value, so a host that passes nothing and one that passes "none" resolve alike.
|
|
625
|
+
selectionGlyph: (() => {
|
|
626
|
+
const v = (p.selectionGlyph == null ? "" : String(p.selectionGlyph)).toLowerCase();
|
|
627
|
+
return v === "dot" || v === "check" ? v : void 0;
|
|
628
|
+
})(),
|
|
629
|
+
// A host FACT from the generate answer, true only for a literal true: silence never suppresses anything.
|
|
630
|
+
suppressSelectionGlyph: p.suppressSelectionGlyph === true ? true : void 0,
|
|
618
631
|
onSelect: p.onSelect,
|
|
619
632
|
// Control gestures (1.10.0). Passed straight through like onSelect: the host owns what a gesture MEANS,
|
|
620
633
|
// and a host that supplies nothing leaves every control behaving exactly as before.
|
|
@@ -2208,12 +2221,209 @@ function createChartHost(container, config) {
|
|
|
2208
2221
|
} catch {
|
|
2209
2222
|
}
|
|
2210
2223
|
};
|
|
2224
|
+
const GLYPH_LAYER_CLASS = "bic-selection-glyphs";
|
|
2225
|
+
let glyphPositionWas = null;
|
|
2226
|
+
let glyphObserver = null;
|
|
2227
|
+
let glyphResize = null;
|
|
2228
|
+
let glyphSize = "";
|
|
2229
|
+
let glyphQueued = false;
|
|
2230
|
+
let glyphQueuedReport = false;
|
|
2231
|
+
let glyphReported = "";
|
|
2232
|
+
const sizeOfContainer = () => `${container.offsetWidth ?? 0}x${container.offsetHeight ?? 0}`;
|
|
2233
|
+
const glyphBlind = `.${GLYPH_LAYER_CLASS}, .${LASSO_OUTLINE_CLASS}`;
|
|
2234
|
+
const movesAMark = (r) => {
|
|
2235
|
+
const t = r.target;
|
|
2236
|
+
if (!t || t.closest?.(glyphBlind)) return false;
|
|
2237
|
+
return !!(t.classList?.contains(MARK_CLASS) || t.querySelector?.(`.${MARK_CLASS}`));
|
|
2238
|
+
};
|
|
2239
|
+
const queueGlyphs = (reportIfChanged) => {
|
|
2240
|
+
if (reportIfChanged) glyphQueuedReport = true;
|
|
2241
|
+
if (glyphQueued) return;
|
|
2242
|
+
glyphQueued = true;
|
|
2243
|
+
const run = () => {
|
|
2244
|
+
const r = glyphQueuedReport;
|
|
2245
|
+
glyphQueued = false;
|
|
2246
|
+
glyphQueuedReport = false;
|
|
2247
|
+
if (glyphObserver || glyphResize) paintGlyphLayer(r ? "if-changed" : false);
|
|
2248
|
+
};
|
|
2249
|
+
if (win?.requestAnimationFrame) win.requestAnimationFrame(run);
|
|
2250
|
+
else setTimeout(run, 16);
|
|
2251
|
+
};
|
|
2252
|
+
const followGlyphs = (on) => {
|
|
2253
|
+
if (!on) {
|
|
2254
|
+
if (glyphObserver) {
|
|
2255
|
+
glyphObserver.disconnect();
|
|
2256
|
+
glyphObserver = null;
|
|
2257
|
+
}
|
|
2258
|
+
if (glyphResize) {
|
|
2259
|
+
glyphResize.disconnect();
|
|
2260
|
+
glyphResize = null;
|
|
2261
|
+
}
|
|
2262
|
+
return;
|
|
2263
|
+
}
|
|
2264
|
+
const MO = win?.MutationObserver;
|
|
2265
|
+
if (!glyphObserver && MO) {
|
|
2266
|
+
glyphObserver = new MO((records) => {
|
|
2267
|
+
if (!glyphQueued && records.some(movesAMark)) queueGlyphs(false);
|
|
2268
|
+
});
|
|
2269
|
+
glyphObserver.observe(container, {
|
|
2270
|
+
subtree: true,
|
|
2271
|
+
attributes: true,
|
|
2272
|
+
attributeFilter: [
|
|
2273
|
+
"transform",
|
|
2274
|
+
"d",
|
|
2275
|
+
"x",
|
|
2276
|
+
"y",
|
|
2277
|
+
"cx",
|
|
2278
|
+
"cy",
|
|
2279
|
+
"points",
|
|
2280
|
+
"width",
|
|
2281
|
+
"height",
|
|
2282
|
+
"visibility",
|
|
2283
|
+
"opacity",
|
|
2284
|
+
"style",
|
|
2285
|
+
"class"
|
|
2286
|
+
]
|
|
2287
|
+
});
|
|
2288
|
+
}
|
|
2289
|
+
const RO = win?.ResizeObserver;
|
|
2290
|
+
if (!glyphResize && RO) {
|
|
2291
|
+
glyphResize = new RO(() => {
|
|
2292
|
+
if (sizeOfContainer() !== glyphSize) queueGlyphs(true);
|
|
2293
|
+
});
|
|
2294
|
+
glyphResize.observe(container);
|
|
2295
|
+
}
|
|
2296
|
+
};
|
|
2297
|
+
const markShown = (m) => {
|
|
2298
|
+
try {
|
|
2299
|
+
const cv = m.checkVisibility;
|
|
2300
|
+
if (typeof cv === "function") return cv.call(m, { visibilityProperty: true, opacityProperty: true }) !== false;
|
|
2301
|
+
const cs = win?.getComputedStyle;
|
|
2302
|
+
if (typeof cs !== "function") return true;
|
|
2303
|
+
const own = cs.call(win, m);
|
|
2304
|
+
if (own.visibility === "hidden" || own.visibility === "collapse") return false;
|
|
2305
|
+
for (let el = m; el && el !== container; el = el.parentElement) {
|
|
2306
|
+
const s = el === m ? own : cs.call(win, el);
|
|
2307
|
+
if (s.display === "none" || s.opacity !== "" && parseFloat(s.opacity) === 0) return false;
|
|
2308
|
+
}
|
|
2309
|
+
} catch {
|
|
2310
|
+
}
|
|
2311
|
+
return true;
|
|
2312
|
+
};
|
|
2313
|
+
const glyphWindows = () => {
|
|
2314
|
+
const windowOf = /* @__PURE__ */ new Map();
|
|
2315
|
+
const read = (el) => {
|
|
2316
|
+
if (!windowOf.has(el)) {
|
|
2317
|
+
let w = null;
|
|
2318
|
+
try {
|
|
2319
|
+
if ((el.tagName || "").toLowerCase() === "svg") {
|
|
2320
|
+
const r = el.getBoundingClientRect();
|
|
2321
|
+
if (r.width > 0 && r.height > 0) w = r;
|
|
2322
|
+
} else if (el.hasAttribute?.("clip-path")) w = clipWindowOf(el);
|
|
2323
|
+
} catch {
|
|
2324
|
+
w = null;
|
|
2325
|
+
}
|
|
2326
|
+
windowOf.set(el, w);
|
|
2327
|
+
}
|
|
2328
|
+
return windowOf.get(el) ?? null;
|
|
2329
|
+
};
|
|
2330
|
+
const EPS2 = 0.5;
|
|
2331
|
+
return (m, x, y) => {
|
|
2332
|
+
for (let el = m; el && el !== container; el = el.parentElement) {
|
|
2333
|
+
const w = read(el);
|
|
2334
|
+
if (w && (x < w.left - EPS2 || x > w.right + EPS2 || y < w.top - EPS2 || y > w.bottom + EPS2)) return false;
|
|
2335
|
+
}
|
|
2336
|
+
return true;
|
|
2337
|
+
};
|
|
2338
|
+
};
|
|
2339
|
+
const paintGlyphLayer = (report = true) => {
|
|
2340
|
+
if (destroyed) return;
|
|
2341
|
+
let follow = false;
|
|
2342
|
+
try {
|
|
2343
|
+
let layer = container.querySelector(`:scope > .${GLYPH_LAYER_CLASS}`);
|
|
2344
|
+
clearSelectionGlyphs(layer);
|
|
2345
|
+
const mode = resolved.selectionGlyph;
|
|
2346
|
+
if (mode !== "dot" && mode !== "check") {
|
|
2347
|
+
glyphReported = "";
|
|
2348
|
+
return;
|
|
2349
|
+
}
|
|
2350
|
+
const active = !!current && current.length > 0 && !selectionIsPeriod;
|
|
2351
|
+
if (!active) {
|
|
2352
|
+
glyphReported = "";
|
|
2353
|
+
return;
|
|
2354
|
+
}
|
|
2355
|
+
if (resolved.suppressSelectionGlyph) {
|
|
2356
|
+
if (report === true) try {
|
|
2357
|
+
config.onSelectionGlyphs?.({ mode, drawn: 0, total: 0, suppressed: true });
|
|
2358
|
+
} catch {
|
|
2359
|
+
}
|
|
2360
|
+
glyphReported = "";
|
|
2361
|
+
return;
|
|
2362
|
+
}
|
|
2363
|
+
follow = true;
|
|
2364
|
+
if (!layer) {
|
|
2365
|
+
layer = doc.createElement("div");
|
|
2366
|
+
layer.className = GLYPH_LAYER_CLASS;
|
|
2367
|
+
layer.setAttribute("aria-hidden", "true");
|
|
2368
|
+
Object.assign(layer.style, {
|
|
2369
|
+
position: "absolute",
|
|
2370
|
+
left: "0",
|
|
2371
|
+
top: "0",
|
|
2372
|
+
width: "0",
|
|
2373
|
+
height: "0",
|
|
2374
|
+
overflow: "hidden",
|
|
2375
|
+
pointerEvents: "none",
|
|
2376
|
+
zIndex: "1"
|
|
2377
|
+
});
|
|
2378
|
+
try {
|
|
2379
|
+
const pos = win?.getComputedStyle?.(container)?.position || container.style.position;
|
|
2380
|
+
if (!pos || pos === "static") {
|
|
2381
|
+
const was = container.style.position;
|
|
2382
|
+
container.style.position = "relative";
|
|
2383
|
+
if (glyphPositionWas === null) glyphPositionWas = was;
|
|
2384
|
+
}
|
|
2385
|
+
} catch {
|
|
2386
|
+
}
|
|
2387
|
+
container.appendChild(layer);
|
|
2388
|
+
}
|
|
2389
|
+
layer.style.width = "0";
|
|
2390
|
+
layer.style.height = "0";
|
|
2391
|
+
const sw = container.scrollWidth || 0, sh = container.scrollHeight || 0;
|
|
2392
|
+
layer.style.width = `${sw}px`;
|
|
2393
|
+
layer.style.height = `${sh}px`;
|
|
2394
|
+
glyphSize = sizeOfContainer();
|
|
2395
|
+
const centers = [];
|
|
2396
|
+
collectGlyphCentersWhere(container, layer.getBoundingClientRect(), centers, { shown: markShown, at: glyphWindows() });
|
|
2397
|
+
const hc = !!resolved.isHighContrast;
|
|
2398
|
+
const drawn = centers.length ? paintSelectionGlyphs(layer, centers, {
|
|
2399
|
+
symbol: mode === "check" ? "\u2713" : "\u25CF",
|
|
2400
|
+
color: hc ? resolved.themeFg || "#111" : "#111",
|
|
2401
|
+
halo: hc ? resolved.themeBg || "#fff" : "#fff"
|
|
2402
|
+
}) : 0;
|
|
2403
|
+
const said = `${mode}:${drawn}:${centers.length}`;
|
|
2404
|
+
if (report === true || report === "if-changed" && said !== glyphReported) {
|
|
2405
|
+
glyphReported = said;
|
|
2406
|
+
try {
|
|
2407
|
+
config.onSelectionGlyphs?.({ mode, drawn, total: centers.length, suppressed: false });
|
|
2408
|
+
} catch {
|
|
2409
|
+
}
|
|
2410
|
+
}
|
|
2411
|
+
} catch {
|
|
2412
|
+
} finally {
|
|
2413
|
+
try {
|
|
2414
|
+
followGlyphs(follow);
|
|
2415
|
+
glyphObserver?.takeRecords();
|
|
2416
|
+
} catch {
|
|
2417
|
+
}
|
|
2418
|
+
}
|
|
2419
|
+
};
|
|
2211
2420
|
const notify = (rowIdxs, source, tick, fromChart = false) => {
|
|
2212
2421
|
current = rowIdxs;
|
|
2213
2422
|
selectionFromChart = rowIdxs.length > 0 && fromChart;
|
|
2214
2423
|
activeTickEl = rowIdxs.length ? tick ?? null : null;
|
|
2215
2424
|
selectionIsPeriod = rowIdxs.length > 0 && periodTickSuppressesFeedback(!!tick, chartOwnsTimeline(container));
|
|
2216
2425
|
paintSelection();
|
|
2426
|
+
paintGlyphLayer();
|
|
2217
2427
|
for (const cb of subs) {
|
|
2218
2428
|
try {
|
|
2219
2429
|
cb(rowIdxs, source);
|
|
@@ -2313,6 +2523,20 @@ function createChartHost(container, config) {
|
|
|
2313
2523
|
}
|
|
2314
2524
|
}
|
|
2315
2525
|
};
|
|
2526
|
+
const keepScroll = config.restoreScroll !== false;
|
|
2527
|
+
let chartSource;
|
|
2528
|
+
const scrollKey = () => {
|
|
2529
|
+
if (config.code) return config.code;
|
|
2530
|
+
if (chartSource === void 0 && typeof config.renderFn === "function") {
|
|
2531
|
+
try {
|
|
2532
|
+
chartSource = Function.prototype.toString.call(config.renderFn);
|
|
2533
|
+
} catch {
|
|
2534
|
+
return config.renderFn;
|
|
2535
|
+
}
|
|
2536
|
+
}
|
|
2537
|
+
return chartSource;
|
|
2538
|
+
};
|
|
2539
|
+
let hasRendered = false;
|
|
2316
2540
|
const runPostRenderPasses = () => {
|
|
2317
2541
|
if (zoomMemory && zoomCap) {
|
|
2318
2542
|
try {
|
|
@@ -2400,9 +2624,11 @@ function createChartHost(container, config) {
|
|
|
2400
2624
|
} catch {
|
|
2401
2625
|
}
|
|
2402
2626
|
}
|
|
2627
|
+
const scrollMem = takeScroll(container);
|
|
2403
2628
|
if (fitOpts !== false) {
|
|
2404
2629
|
try {
|
|
2405
|
-
const
|
|
2630
|
+
const base = fitOpts === true ? {} : fitOpts;
|
|
2631
|
+
const r = fitRenderedChart(container, keepScroll ? { ...base, restoreScroll: { memory: scrollMem, key: scrollKey() } } : base);
|
|
2406
2632
|
config.onFit?.(r);
|
|
2407
2633
|
} catch {
|
|
2408
2634
|
}
|
|
@@ -2411,6 +2637,7 @@ function createChartHost(container, config) {
|
|
|
2411
2637
|
drawAnnotations();
|
|
2412
2638
|
} catch {
|
|
2413
2639
|
}
|
|
2640
|
+
paintGlyphLayer();
|
|
2414
2641
|
try {
|
|
2415
2642
|
lasso = installLasso({
|
|
2416
2643
|
container,
|
|
@@ -2437,9 +2664,12 @@ function createChartHost(container, config) {
|
|
|
2437
2664
|
if (destroyed) return;
|
|
2438
2665
|
const seq2 = ++renderSeq;
|
|
2439
2666
|
stopAnim();
|
|
2667
|
+
followGlyphs(false);
|
|
2440
2668
|
disposeLasso();
|
|
2441
2669
|
flushZoom();
|
|
2670
|
+
if (hasRendered && keepScroll) rememberScroll(container, scrollKey());
|
|
2442
2671
|
container.innerHTML = "";
|
|
2672
|
+
hasRendered = true;
|
|
2443
2673
|
if (!renderFn) {
|
|
2444
2674
|
if (!config.code) throw new Error("createChartHost: provide code or renderFn");
|
|
2445
2675
|
renderFn = compileRenderFn(config.code, win, doc, chartD3);
|
|
@@ -2461,6 +2691,8 @@ function createChartHost(container, config) {
|
|
|
2461
2691
|
if (resolved.geoPoint === void 0 && data.geoPoint) resolved = { ...resolved, geoPoint: data.geoPoint };
|
|
2462
2692
|
if (resolved.geoPointDest === void 0 && data.geoPointDest) resolved = { ...resolved, geoPointDest: data.geoPointDest };
|
|
2463
2693
|
if (resolved.dateCellsAreUtcDays === void 0 && data.dateCellsAreUtcDays) resolved = { ...resolved, dateCellsAreUtcDays: true };
|
|
2694
|
+
if (resolved.suppressSelectionGlyph === void 0 && data.meta?.suppressSelectionGlyph === true)
|
|
2695
|
+
resolved = { ...resolved, suppressSelectionGlyph: true };
|
|
2464
2696
|
let outcome;
|
|
2465
2697
|
zoomCap = null;
|
|
2466
2698
|
if (zoomMemory && config.code && !config.renderFn) {
|
|
@@ -2604,9 +2836,18 @@ function createChartHost(container, config) {
|
|
|
2604
2836
|
dimVarSet = false;
|
|
2605
2837
|
}
|
|
2606
2838
|
annotationLayer.destroy();
|
|
2839
|
+
if (hasRendered && keepScroll) rememberScroll(container, scrollKey());
|
|
2607
2840
|
unpinScrolledAxis(container);
|
|
2608
2841
|
flushZoom();
|
|
2842
|
+
followGlyphs(false);
|
|
2609
2843
|
container.innerHTML = "";
|
|
2844
|
+
if (glyphPositionWas !== null) {
|
|
2845
|
+
try {
|
|
2846
|
+
if (container.style.position === "relative") container.style.position = glyphPositionWas;
|
|
2847
|
+
} catch {
|
|
2848
|
+
}
|
|
2849
|
+
glyphPositionWas = null;
|
|
2850
|
+
}
|
|
2610
2851
|
}
|
|
2611
2852
|
};
|
|
2612
2853
|
return host;
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
/*! @bicharts/chart-host — Apache-2.0. Bundled reference data: GeoNames (https://www.geonames.org/) CC BY 4.0; Natural Earth and US Census/TIGER (public domain). Full text: NOTICE in this package. */
|
|
2
2
|
import {
|
|
3
|
+
CONTAINER_SLOT_SCROLL,
|
|
3
4
|
SNAPSHOT_SVG_ATTR
|
|
4
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-45VILLJT.mjs";
|
|
5
6
|
|
|
6
7
|
// src/fit.ts
|
|
7
8
|
var SCROLL_SLACK_PX = 8;
|
|
@@ -104,6 +105,15 @@ function axisPinPlacement(band, scrollTop, viewportH) {
|
|
|
104
105
|
if (band.bottom > scrollTop + viewportH) return "bottom";
|
|
105
106
|
return null;
|
|
106
107
|
}
|
|
108
|
+
var nonNegative = (n) => typeof n === "number" && isFinite(n) && n > 0 ? n : 0;
|
|
109
|
+
function planScrollRestore(saved, key, m) {
|
|
110
|
+
if (!saved || key === void 0 || key === null || saved.key !== key) return { x: 0, y: 0 };
|
|
111
|
+
const room = (content, view) => Math.max(0, nonNegative(content) - nonNegative(view));
|
|
112
|
+
return {
|
|
113
|
+
x: m.overflowX === "auto" ? Math.min(nonNegative(saved.x), room(m.scrollWidth, m.clientWidth)) : 0,
|
|
114
|
+
y: m.overflowY === "auto" ? Math.min(nonNegative(saved.y), room(m.scrollHeight, m.clientHeight)) : 0
|
|
115
|
+
};
|
|
116
|
+
}
|
|
107
117
|
|
|
108
118
|
// src/fitDom.ts
|
|
109
119
|
var FIT_WALK_CAP = 8e3;
|
|
@@ -256,6 +266,28 @@ function unpinScrolledAxis(container) {
|
|
|
256
266
|
} catch {
|
|
257
267
|
}
|
|
258
268
|
}
|
|
269
|
+
function rememberScroll(container, key) {
|
|
270
|
+
if (!container) return;
|
|
271
|
+
try {
|
|
272
|
+
const slot = container;
|
|
273
|
+
if (slot[CONTAINER_SLOT_SCROLL]) return;
|
|
274
|
+
if (container.querySelector(".llm-mm-scroll")) return;
|
|
275
|
+
const x = container.scrollLeft, y = container.scrollTop;
|
|
276
|
+
if (x > 0 || y > 0) slot[CONTAINER_SLOT_SCROLL] = { key, x, y };
|
|
277
|
+
} catch {
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
function takeScroll(container) {
|
|
281
|
+
if (!container) return null;
|
|
282
|
+
try {
|
|
283
|
+
const slot = container;
|
|
284
|
+
const m = slot[CONTAINER_SLOT_SCROLL] ?? null;
|
|
285
|
+
delete slot[CONTAINER_SLOT_SCROLL];
|
|
286
|
+
return m;
|
|
287
|
+
} catch {
|
|
288
|
+
return null;
|
|
289
|
+
}
|
|
290
|
+
}
|
|
259
291
|
function textHidden(t, view) {
|
|
260
292
|
if (t.getAttribute("display") === "none" || t.getAttribute("visibility") === "hidden") return true;
|
|
261
293
|
try {
|
|
@@ -476,7 +508,8 @@ function fitRenderedChart(container, opts = {}) {
|
|
|
476
508
|
overflowX: "hidden",
|
|
477
509
|
overflowY: "hidden",
|
|
478
510
|
reading: null,
|
|
479
|
-
axisPin: noPin("no-container")
|
|
511
|
+
axisPin: noPin("no-container"),
|
|
512
|
+
scrolledTo: null
|
|
480
513
|
};
|
|
481
514
|
if (!container) return result;
|
|
482
515
|
try {
|
|
@@ -537,6 +570,19 @@ function fitRenderedChart(container, opts = {}) {
|
|
|
537
570
|
if (opts.applyOverflow !== false) {
|
|
538
571
|
container.style.overflowX = fit.overflowX;
|
|
539
572
|
container.style.overflowY = fit.overflowY;
|
|
573
|
+
if (opts.restoreScroll) {
|
|
574
|
+
const to = planScrollRestore(opts.restoreScroll.memory, opts.restoreScroll.key, {
|
|
575
|
+
scrollWidth: container.scrollWidth,
|
|
576
|
+
scrollHeight: container.scrollHeight,
|
|
577
|
+
clientWidth: container.clientWidth,
|
|
578
|
+
clientHeight: container.clientHeight,
|
|
579
|
+
overflowX: fit.overflowX,
|
|
580
|
+
overflowY: fit.overflowY
|
|
581
|
+
});
|
|
582
|
+
if (container.scrollLeft !== to.x) container.scrollLeft = to.x;
|
|
583
|
+
if (container.scrollTop !== to.y) container.scrollTop = to.y;
|
|
584
|
+
result.scrolledTo = to;
|
|
585
|
+
}
|
|
540
586
|
if (fit.overflowY !== "auto") {
|
|
541
587
|
unpinScrolledAxis(container);
|
|
542
588
|
result.axisPin = noPin("not-scrolling");
|
|
@@ -571,12 +617,15 @@ export {
|
|
|
571
617
|
labelBand,
|
|
572
618
|
planAxisPin,
|
|
573
619
|
axisPinPlacement,
|
|
620
|
+
planScrollRestore,
|
|
574
621
|
ctmScaleOf,
|
|
575
622
|
svgInkReach,
|
|
576
623
|
clipWindowOf,
|
|
577
624
|
measureContainerBoxes,
|
|
578
625
|
fitReadingFor,
|
|
579
626
|
unpinScrolledAxis,
|
|
627
|
+
rememberScroll,
|
|
628
|
+
takeScroll,
|
|
580
629
|
pinScrolledAxis,
|
|
581
630
|
fitRenderedChart
|
|
582
631
|
};
|
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
gestureWasDrag,
|
|
5
5
|
isInsideControl,
|
|
6
6
|
rowIdxsFromMark
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-VEVBXK44.mjs";
|
|
8
8
|
import {
|
|
9
9
|
AXIS_FILTER_CLASS,
|
|
10
10
|
CONTROL_CLASS,
|
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
MARK_CLASS,
|
|
13
13
|
ROW_IDX_ATTR,
|
|
14
14
|
SNAPSHOT_SVG_ATTR
|
|
15
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-45VILLJT.mjs";
|
|
16
16
|
|
|
17
17
|
// src/lasso.ts
|
|
18
18
|
var LASSO_ROW_CAP = 5e3;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/*! @bicharts/chart-host — Apache-2.0. Bundled reference data: GeoNames (https://www.geonames.org/) CC BY 4.0; Natural Earth and US Census/TIGER (public domain). Full text: NOTICE in this package. */
|
|
2
2
|
import {
|
|
3
3
|
SNAPSHOT_SVG_ATTR
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-45VILLJT.mjs";
|
|
5
5
|
|
|
6
6
|
// src/snapshot.ts
|
|
7
7
|
var DEFAULT_TIMEOUT_MS = 2e3;
|
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
SELECTION_RULE_ATTR,
|
|
9
9
|
SELECTION_RULE_CLICKED_MARKS,
|
|
10
10
|
XFILTER_REFRESH_EVENT
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-45VILLJT.mjs";
|
|
12
12
|
|
|
13
13
|
// src/selection.ts
|
|
14
14
|
function rowIdxsFromMark(el) {
|
|
@@ -304,8 +304,12 @@ function createMarkResolver(env) {
|
|
|
304
304
|
return { isInvisibleStrokePath, distToPathCenterline, refineHitCorridor, findMark, rowIdxsFromMark, penetrateOverlayAt, resolveByGeometry };
|
|
305
305
|
}
|
|
306
306
|
function collectD3GlyphCenters(container, baseRect, out) {
|
|
307
|
+
collectGlyphCentersWhere(container, baseRect, out);
|
|
308
|
+
}
|
|
309
|
+
function collectGlyphCentersWhere(container, baseRect, out, filter) {
|
|
307
310
|
const Point = container.ownerDocument?.defaultView?.DOMPoint ?? globalThis.DOMPoint;
|
|
308
|
-
|
|
311
|
+
let marks = container.querySelectorAll(`.${MARK_CLASS}.${MARK_SELECTED_CLASS}`);
|
|
312
|
+
if (filter?.shown) marks = Array.from(marks).filter((m) => filter.shown(m));
|
|
309
313
|
const rects = [];
|
|
310
314
|
for (let i = 0; i < marks.length; i++) {
|
|
311
315
|
const r = marks[i].getBoundingClientRect();
|
|
@@ -385,6 +389,7 @@ function collectD3GlyphCenters(container, baseRect, out) {
|
|
|
385
389
|
sx = isRect ? r.left + r.width * 0.8 : r.left + r.width / 2;
|
|
386
390
|
sy = isRect ? r.top + r.height * 0.2 : r.top + r.height / 2;
|
|
387
391
|
}
|
|
392
|
+
if (filter?.at && !filter.at(el, sx, sy)) continue;
|
|
388
393
|
out.push({ x: sx - baseRect.left, y: sy - baseRect.top });
|
|
389
394
|
}
|
|
390
395
|
}
|
|
@@ -439,6 +444,7 @@ export {
|
|
|
439
444
|
clickWasDrag,
|
|
440
445
|
createMarkResolver,
|
|
441
446
|
collectD3GlyphCenters,
|
|
447
|
+
collectGlyphCentersWhere,
|
|
442
448
|
SELECTION_GLYPH_CLASS,
|
|
443
449
|
clearSelectionGlyphs,
|
|
444
450
|
paintSelectionGlyphs
|
package/dist/index.mjs
CHANGED
|
@@ -15,7 +15,7 @@ import {
|
|
|
15
15
|
svgNaturalSize,
|
|
16
16
|
svgToDataUrl,
|
|
17
17
|
tableHostOf
|
|
18
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-VC3Z5CH7.mjs";
|
|
19
19
|
import {
|
|
20
20
|
ANNOTATION_CLASS,
|
|
21
21
|
ANNOTATION_LAYER_CLASS,
|
|
@@ -97,7 +97,7 @@ import {
|
|
|
97
97
|
toRGBA,
|
|
98
98
|
toSourceRows,
|
|
99
99
|
valuePlacementFlag
|
|
100
|
-
} from "./chunk-
|
|
100
|
+
} from "./chunk-FHHT7DBM.mjs";
|
|
101
101
|
import {
|
|
102
102
|
LASSO_AXES_SLOT,
|
|
103
103
|
LASSO_COUNT_CLASS,
|
|
@@ -122,13 +122,13 @@ import {
|
|
|
122
122
|
lassoVerdict,
|
|
123
123
|
pointInShape,
|
|
124
124
|
registerLassoAction
|
|
125
|
-
} from "./chunk-
|
|
125
|
+
} from "./chunk-QHMLMF4L.mjs";
|
|
126
126
|
import {
|
|
127
127
|
MIN_HIT_BAND_PX,
|
|
128
128
|
censusHitBands,
|
|
129
129
|
ensureCrossfilterHitTargets,
|
|
130
130
|
hitBandFlag
|
|
131
|
-
} from "./chunk-
|
|
131
|
+
} from "./chunk-PDVEIW42.mjs";
|
|
132
132
|
import {
|
|
133
133
|
CONTAINER_SLOT_PRESS_AT,
|
|
134
134
|
DRAG_NOT_CLICK_PX,
|
|
@@ -153,7 +153,7 @@ import {
|
|
|
153
153
|
selectionRuleOf,
|
|
154
154
|
trackPress,
|
|
155
155
|
validRowSet
|
|
156
|
-
} from "./chunk-
|
|
156
|
+
} from "./chunk-VEVBXK44.mjs";
|
|
157
157
|
import {
|
|
158
158
|
AXIS_PIN_BAND_PAD_PX,
|
|
159
159
|
AXIS_PIN_MAX_BAND_FRACTION,
|
|
@@ -176,10 +176,13 @@ import {
|
|
|
176
176
|
pinScrolledAxis,
|
|
177
177
|
planAxisPin,
|
|
178
178
|
planFrameGrow,
|
|
179
|
+
planScrollRestore,
|
|
180
|
+
rememberScroll,
|
|
179
181
|
scrollFitFor,
|
|
180
182
|
svgInkReach,
|
|
183
|
+
takeScroll,
|
|
181
184
|
unpinScrolledAxis
|
|
182
|
-
} from "./chunk-
|
|
185
|
+
} from "./chunk-NNLBFIWU.mjs";
|
|
183
186
|
import {
|
|
184
187
|
_3,
|
|
185
188
|
l,
|
|
@@ -205,6 +208,7 @@ import {
|
|
|
205
208
|
CONTAINER_SLOT_ANIM_STOP,
|
|
206
209
|
CONTAINER_SLOT_CLICKED_MARKS,
|
|
207
210
|
CONTAINER_SLOT_INITIAL_XF_MARK,
|
|
211
|
+
CONTAINER_SLOT_SCROLL,
|
|
208
212
|
CONTAINER_SLOT_UI_STATE,
|
|
209
213
|
CONTAINER_SLOT_XF_CLEAR,
|
|
210
214
|
CONTROL_CLASS,
|
|
@@ -237,7 +241,7 @@ import {
|
|
|
237
241
|
chartOwnsTimeline,
|
|
238
242
|
periodTickSuppressesFeedback,
|
|
239
243
|
withoutViewOnlyKeys
|
|
240
|
-
} from "./chunk-
|
|
244
|
+
} from "./chunk-45VILLJT.mjs";
|
|
241
245
|
import "./chunk-GHODWOAL.mjs";
|
|
242
246
|
|
|
243
247
|
// src/optionsVocabulary.ts
|
|
@@ -2154,6 +2158,7 @@ export {
|
|
|
2154
2158
|
CONTAINER_SLOT_CLICKED_MARKS,
|
|
2155
2159
|
CONTAINER_SLOT_INITIAL_XF_MARK,
|
|
2156
2160
|
CONTAINER_SLOT_PRESS_AT,
|
|
2161
|
+
CONTAINER_SLOT_SCROLL,
|
|
2157
2162
|
CONTAINER_SLOT_UI_STATE,
|
|
2158
2163
|
CONTAINER_SLOT_XF_CLEAR,
|
|
2159
2164
|
CONTROL_CLASS,
|
|
@@ -2393,6 +2398,7 @@ export {
|
|
|
2393
2398
|
pinScrolledAxis,
|
|
2394
2399
|
planAxisPin,
|
|
2395
2400
|
planFrameGrow,
|
|
2401
|
+
planScrollRestore,
|
|
2396
2402
|
planSelectionPaint,
|
|
2397
2403
|
planTrivialChart,
|
|
2398
2404
|
pointInShape,
|
|
@@ -2429,6 +2435,7 @@ export {
|
|
|
2429
2435
|
registerGeoAsset,
|
|
2430
2436
|
registerLassoAction,
|
|
2431
2437
|
relativeLuminance,
|
|
2438
|
+
rememberScroll,
|
|
2432
2439
|
requiredD3Plugins,
|
|
2433
2440
|
resolveAutoColorScale,
|
|
2434
2441
|
resolveOptions,
|
|
@@ -2455,6 +2462,7 @@ export {
|
|
|
2455
2462
|
svgToDataUrl,
|
|
2456
2463
|
syncMemberSelection,
|
|
2457
2464
|
tableHostOf,
|
|
2465
|
+
takeScroll,
|
|
2458
2466
|
toRGBA,
|
|
2459
2467
|
toSourceRows,
|
|
2460
2468
|
trackPress,
|
package/dist/legend-fit.mjs
CHANGED
|
@@ -2,13 +2,13 @@
|
|
|
2
2
|
import {
|
|
3
3
|
chartSvgOf,
|
|
4
4
|
tableHostOf
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-VC3Z5CH7.mjs";
|
|
6
6
|
import {
|
|
7
7
|
FIT_CONTENT_SELECTOR,
|
|
8
8
|
ctmScaleOf,
|
|
9
9
|
isPhantomBox
|
|
10
|
-
} from "./chunk-
|
|
11
|
-
import "./chunk-
|
|
10
|
+
} from "./chunk-NNLBFIWU.mjs";
|
|
11
|
+
import "./chunk-45VILLJT.mjs";
|
|
12
12
|
import "./chunk-GHODWOAL.mjs";
|
|
13
13
|
|
|
14
14
|
// src/legendFit/legendReconcile.ts
|
package/dist/page.mjs
CHANGED
|
@@ -14,10 +14,10 @@ import {
|
|
|
14
14
|
readControls,
|
|
15
15
|
viewFromToken,
|
|
16
16
|
viewToken
|
|
17
|
-
} from "./chunk-
|
|
18
|
-
import "./chunk-
|
|
19
|
-
import "./chunk-
|
|
20
|
-
import "./chunk-
|
|
17
|
+
} from "./chunk-CR7DSJVG.mjs";
|
|
18
|
+
import "./chunk-QHMLMF4L.mjs";
|
|
19
|
+
import "./chunk-VEVBXK44.mjs";
|
|
20
|
+
import "./chunk-45VILLJT.mjs";
|
|
21
21
|
import "./chunk-GHODWOAL.mjs";
|
|
22
22
|
export {
|
|
23
23
|
LINKED_HOVER_CLASS,
|
package/dist/react.mjs
CHANGED
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
payloadRowReader,
|
|
14
14
|
viewFromToken,
|
|
15
15
|
viewToken
|
|
16
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-CR7DSJVG.mjs";
|
|
17
17
|
import {
|
|
18
18
|
assembleD3,
|
|
19
19
|
createChartGroup,
|
|
@@ -22,14 +22,14 @@ import {
|
|
|
22
22
|
loadGeo,
|
|
23
23
|
syncMemberSelection,
|
|
24
24
|
toSourceRows
|
|
25
|
-
} from "./chunk-
|
|
26
|
-
import "./chunk-
|
|
27
|
-
import "./chunk-
|
|
28
|
-
import "./chunk-
|
|
29
|
-
import "./chunk-
|
|
25
|
+
} from "./chunk-FHHT7DBM.mjs";
|
|
26
|
+
import "./chunk-QHMLMF4L.mjs";
|
|
27
|
+
import "./chunk-PDVEIW42.mjs";
|
|
28
|
+
import "./chunk-VEVBXK44.mjs";
|
|
29
|
+
import "./chunk-NNLBFIWU.mjs";
|
|
30
30
|
import "./chunk-KQN5C7SZ.mjs";
|
|
31
31
|
import "./chunk-A2GMXZP7.mjs";
|
|
32
|
-
import "./chunk-
|
|
32
|
+
import "./chunk-45VILLJT.mjs";
|
|
33
33
|
import "./chunk-GHODWOAL.mjs";
|
|
34
34
|
|
|
35
35
|
// src/react.tsx
|
|
@@ -69,7 +69,9 @@ function BicChart(props) {
|
|
|
69
69
|
viewState,
|
|
70
70
|
zoomMemory,
|
|
71
71
|
labelContrast,
|
|
72
|
+
restoreScroll,
|
|
72
73
|
onLabelContrast,
|
|
74
|
+
onSelectionGlyphs,
|
|
73
75
|
layoutPass,
|
|
74
76
|
onInvalidSentinel,
|
|
75
77
|
id,
|
|
@@ -116,6 +118,8 @@ function BicChart(props) {
|
|
|
116
118
|
onSelectRef.current = onSelect;
|
|
117
119
|
const onLabelContrastRef = useRef(onLabelContrast);
|
|
118
120
|
onLabelContrastRef.current = onLabelContrast;
|
|
121
|
+
const onSelectionGlyphsRef = useRef(onSelectionGlyphs);
|
|
122
|
+
onSelectionGlyphsRef.current = onSelectionGlyphs;
|
|
119
123
|
const onInvalidSentinelRef = useRef(onInvalidSentinel);
|
|
120
124
|
onInvalidSentinelRef.current = onInvalidSentinel;
|
|
121
125
|
const onAnnotationClickRef = useRef(onAnnotationClick);
|
|
@@ -154,7 +158,9 @@ function BicChart(props) {
|
|
|
154
158
|
zoomMemory,
|
|
155
159
|
labelContrast,
|
|
156
160
|
layoutPass,
|
|
161
|
+
restoreScroll,
|
|
157
162
|
onLabelContrast: (r) => onLabelContrastRef.current?.(r),
|
|
163
|
+
onSelectionGlyphs: (r) => onSelectionGlyphsRef.current?.(r),
|
|
158
164
|
// A GETTER, not a wrapper: the host decides whether to
|
|
159
165
|
// swallow the sentinel throw by whether this is SET, so
|
|
160
166
|
// an always-present wrapper would hide the throw from a
|
|
@@ -185,7 +191,7 @@ function BicChart(props) {
|
|
|
185
191
|
host.destroy();
|
|
186
192
|
hostRef.current = null;
|
|
187
193
|
};
|
|
188
|
-
}, [code, renderFn, d3, geoKind, labelContrast, layoutPass, controls]);
|
|
194
|
+
}, [code, renderFn, d3, geoKind, labelContrast, layoutPass, restoreScroll, controls]);
|
|
189
195
|
useLayoutEffect(() => {
|
|
190
196
|
const host = hostRef.current;
|
|
191
197
|
if (!host || !selects) return;
|
|
@@ -211,7 +217,7 @@ function BicChart(props) {
|
|
|
211
217
|
b.detach();
|
|
212
218
|
if (bindingRef.current === b) bindingRef.current = null;
|
|
213
219
|
};
|
|
214
|
-
}, [selects, code, renderFn, d3, geoKind, labelContrast, layoutPass]);
|
|
220
|
+
}, [selects, code, renderFn, d3, geoKind, labelContrast, layoutPass, restoreScroll]);
|
|
215
221
|
useEffect(() => {
|
|
216
222
|
if (!hostRef.current || !options) return;
|
|
217
223
|
if (builtWithRef.current?.optKey === optKey) return;
|
package/dist/testing.mjs
CHANGED
package/dist/types/contract.d.ts
CHANGED
|
@@ -35,6 +35,7 @@ export declare const CONTAINER_SLOT_ANIM_STOP = "__llmAnimStop";
|
|
|
35
35
|
export declare const CONTAINER_SLOT_XF_CLEAR = "__llmXfClear";
|
|
36
36
|
export declare const CONTAINER_SLOT_INITIAL_XF_MARK = "__llmInitialXfMark";
|
|
37
37
|
export declare const CONTAINER_SLOT_UI_STATE = "__lchUiState";
|
|
38
|
+
export declare const CONTAINER_SLOT_SCROLL = "__lchScroll";
|
|
38
39
|
export declare const CONTAINER_SLOT_CLICKED_MARKS = "__lchClickedMarks";
|
|
39
40
|
export declare const VIEW_ONLY_UI_STATE_KEYS: readonly string[];
|
|
40
41
|
/** The bag with every view-only key removed: what a host persists when the reader has not asked
|
|
@@ -163,6 +164,10 @@ export interface RenderOptions {
|
|
|
163
164
|
/** How far a selection dims the marks outside it, as a share of full opacity (DIM_OPACITY_MIN-1). Absent: the
|
|
164
165
|
* stylesheet decides - DIM_OPACITY_DEFAULT, or whatever the page sets on --lch-dim-opacity. */
|
|
165
166
|
dimOpacity?: number;
|
|
167
|
+
/** A small glyph on each selected mark: "dot" or "check". Absent or "none": no glyph (the default). */
|
|
168
|
+
selectionGlyph?: "none" | "dot" | "check";
|
|
169
|
+
/** A host FACT from the generate answer: this chart's family never takes a selection glyph. */
|
|
170
|
+
suppressSelectionGlyph?: boolean;
|
|
166
171
|
animAutoPlay?: boolean;
|
|
167
172
|
animPlaySpeedMs?: number;
|
|
168
173
|
animLoopDelaySec?: number;
|
package/dist/types/fit.d.ts
CHANGED
|
@@ -90,3 +90,26 @@ export type AxisPinEdge = "top" | "bottom";
|
|
|
90
90
|
* one drawn over it.
|
|
91
91
|
*/
|
|
92
92
|
export declare function axisPinPlacement(band: AxisBand, scrollTop: number, viewportH: number): AxisPinEdge | null;
|
|
93
|
+
/** A reader's scroll offsets and the identity of the chart they were made on. */
|
|
94
|
+
export interface ScrollMemory {
|
|
95
|
+
key: unknown;
|
|
96
|
+
x: number;
|
|
97
|
+
y: number;
|
|
98
|
+
}
|
|
99
|
+
/** What the container reports once the overflow is decided. */
|
|
100
|
+
export interface ScrollMetrics {
|
|
101
|
+
scrollWidth: number;
|
|
102
|
+
scrollHeight: number;
|
|
103
|
+
clientWidth: number;
|
|
104
|
+
clientHeight: number;
|
|
105
|
+
overflowX: string;
|
|
106
|
+
overflowY: string;
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Where the scroll goes after a redraw. The saved offsets when the SAME chart is back, clamped to what the new layout can scroll and
|
|
110
|
+
* applied per axis only where the container scrolls; otherwise the origin. A new chart opens at the top.
|
|
111
|
+
*/
|
|
112
|
+
export declare function planScrollRestore(saved: ScrollMemory | null | undefined, key: unknown, m: ScrollMetrics): {
|
|
113
|
+
x: number;
|
|
114
|
+
y: number;
|
|
115
|
+
};
|
package/dist/types/fitDom.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ContentExtent, MeasuredBox, AxisPinEdge } from "./fit";
|
|
1
|
+
import type { ContentExtent, MeasuredBox, AxisPinEdge, ScrollMemory } from "./fit";
|
|
2
2
|
export declare function ctmScaleOf(m: {
|
|
3
3
|
a: number;
|
|
4
4
|
b: number;
|
|
@@ -59,6 +59,16 @@ export interface FitRenderedChartOptions {
|
|
|
59
59
|
* Set false for a host that draws its own sticky header.
|
|
60
60
|
*/
|
|
61
61
|
pinAxis?: boolean;
|
|
62
|
+
/**
|
|
63
|
+
* Put the reader's scroll back once the overflow is decided: `memory` (what `takeScroll` handed
|
|
64
|
+
* back) is restored only when its key is `key`, the chart now drawn, clamped to what the new
|
|
65
|
+
* layout can scroll and only on an axis that scrolls. Applied before the axis pin, which places
|
|
66
|
+
* its copy from the scroll it finds. Absent, the container is left where the render put it.
|
|
67
|
+
*/
|
|
68
|
+
restoreScroll?: {
|
|
69
|
+
memory: ScrollMemory | null;
|
|
70
|
+
key: unknown;
|
|
71
|
+
};
|
|
62
72
|
}
|
|
63
73
|
export interface FitRenderedChartResult {
|
|
64
74
|
/** The frame was grown, so content that was being clipped is now painted. */
|
|
@@ -73,6 +83,11 @@ export interface FitRenderedChartResult {
|
|
|
73
83
|
reading: FitReading | null;
|
|
74
84
|
/** The axis pin: what was pinned when the container scrolls, or why nothing was. */
|
|
75
85
|
axisPin: AxisPinReport;
|
|
86
|
+
/** Where `restoreScroll` put the container ({0,0} for a different chart), or null when it was not asked or the overflow was not applied. */
|
|
87
|
+
scrolledTo: {
|
|
88
|
+
x: number;
|
|
89
|
+
y: number;
|
|
90
|
+
} | null;
|
|
76
91
|
}
|
|
77
92
|
export interface AxisPinReport {
|
|
78
93
|
pinned: boolean;
|
|
@@ -94,5 +109,13 @@ export interface AxisPinReport {
|
|
|
94
109
|
* when there is none. Hosts that clear the container themselves still need this for the
|
|
95
110
|
* listener, which outlives the overlay. */
|
|
96
111
|
export declare function unpinScrolledAxis(container: HTMLElement | null | undefined): void;
|
|
112
|
+
/**
|
|
113
|
+
* Remember where the container is scrolled, BEFORE the container is cleared. A memory already waiting is kept: a second render that
|
|
114
|
+
* starts before the first one restored sees an emptied (unscrolled) container, and must not overwrite what the reader really did.
|
|
115
|
+
* A diagram that scrolls inside itself remembers its own position, so it is left alone.
|
|
116
|
+
*/
|
|
117
|
+
export declare function rememberScroll(container: HTMLElement | null | undefined, key: unknown): void;
|
|
118
|
+
/** The waiting memory, removed. The one place it is consumed, so a stale memory can never outlive a render. */
|
|
119
|
+
export declare function takeScroll(container: HTMLElement | null | undefined): ScrollMemory | null;
|
|
97
120
|
export declare function pinScrolledAxis(container: HTMLElement | null | undefined, svg: SVGSVGElement | null | undefined): AxisPinReport;
|
|
98
121
|
export declare function fitRenderedChart(container: HTMLElement | null | undefined, opts?: FitRenderedChartOptions): FitRenderedChartResult;
|
package/dist/types/host.d.ts
CHANGED
|
@@ -62,6 +62,9 @@ export interface ChartHostConfig {
|
|
|
62
62
|
meta?: {
|
|
63
63
|
hostContract?: string;
|
|
64
64
|
chart?: string;
|
|
65
|
+
/** The generate answer's fact that this chart's family never takes a selection glyph. Promoted into
|
|
66
|
+
* options.suppressSelectionGlyph, so a host that hands over the whole payload honors it unasked. */
|
|
67
|
+
suppressSelectionGlyph?: boolean;
|
|
65
68
|
};
|
|
66
69
|
};
|
|
67
70
|
/** Generated render() source — compiled exactly like the visual/preview/exec-gate. */
|
|
@@ -178,6 +181,15 @@ export interface ChartHostConfig {
|
|
|
178
181
|
* reading without touching the chart (`grow: false`, `applyOverflow: false`).
|
|
179
182
|
*/
|
|
180
183
|
fit?: boolean | FitRenderedChartOptions;
|
|
184
|
+
/**
|
|
185
|
+
* KEEP THE READER'S SCROLL when the SAME chart is drawn again - a resize, a filter, a theme
|
|
186
|
+
* switch, or a new host on the same element. Default true: the offset is parked on the
|
|
187
|
+
* container before each clear and put back by the fit, clamped to what the new layout can
|
|
188
|
+
* scroll; a different chart (other code, or a renderFn with other source) opens at the top. Pass `false`
|
|
189
|
+
* for a page that manages the container's scrolling itself: nothing is remembered or restored,
|
|
190
|
+
* and a memory an earlier host left on the element is discarded at the next render.
|
|
191
|
+
*/
|
|
192
|
+
restoreScroll?: boolean;
|
|
181
193
|
/** The fit result after each render - what was grown, and how the chart measured. */
|
|
182
194
|
onFit?: (result: FitRenderedChartResult) => void;
|
|
183
195
|
/**
|
|
@@ -199,6 +211,18 @@ export interface ChartHostConfig {
|
|
|
199
211
|
labelContrast?: boolean | LabelContrastOptions;
|
|
200
212
|
/** What the label-contrast pass did after each render - counts, so a host can log them. */
|
|
201
213
|
onLabelContrast?: (report: LabelContrastReport) => void;
|
|
214
|
+
/**
|
|
215
|
+
* What the selection-glyph pass did after each paint of an active selection - counts, so a host can log them.
|
|
216
|
+
* Called only when options.selectionGlyph is "dot" or "check"; `suppressed` is true when the chart's family never
|
|
217
|
+
* takes a glyph (options.suppressSelectionGlyph, or the same fact in data.meta). A repaint that only follows marks
|
|
218
|
+
* moving without a render (a pan, a transition) is not reported again.
|
|
219
|
+
*/
|
|
220
|
+
onSelectionGlyphs?: (report: {
|
|
221
|
+
mode: "dot" | "check";
|
|
222
|
+
drawn: number;
|
|
223
|
+
total: number;
|
|
224
|
+
suppressed: boolean;
|
|
225
|
+
}) => void;
|
|
202
226
|
/**
|
|
203
227
|
* A LAYOUT PASS the host brings, run after every render (both the synchronous and the promise lane, and every
|
|
204
228
|
* setOptions / setData re-render) AFTER the label-contrast pass and BEFORE the hit-target heal, the selection
|
package/dist/types/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { HOST_CONTRACT_VERSION, GEO_POINT_PRECISIONS, MARK_CLASS, LEGEND_MARK_CLASS, AXIS_FILTER_CLASS, ROW_IDX_ATTR, LIFT_SELECTED_CLASS, CONTROL_CLASS, NO_ROW_MARKS_ATTR, SELECTION_RULE_ATTR, SELECTION_RULE_CLICKED_MARKS, MARK_KEY_ATTR, CONTAINER_SLOT_CLICKED_MARKS, SNAPSHOT_SVG_ATTR, XFILTER_REFRESH_EVENT, CONTAINER_SLOT_ANIM_STOP, CONTAINER_SLOT_XF_CLEAR, CONTAINER_SLOT_INITIAL_XF_MARK, CONTAINER_SLOT_UI_STATE, VIEW_ONLY_UI_STATE_KEYS, withoutViewOnlyKeys, HOST_CONTAINER_CLASS, SELECTION_ACTIVE_CLASS, MARK_SELECTED_CLASS, ACTIVE_TICK_CLASS, DIM_OPACITY_VAR, DIM_OPACITY_DEFAULT, DIM_OPACITY_MIN, chartOwnsTimeline, periodTickSuppressesFeedback, ANIM_PLAY_SPEED_DEFAULT, ANIM_PLAY_SPEED_MIN, ANIM_PLAY_SPEED_MAX, ANIM_LOOP_DELAY_DEFAULT, ANIM_LOOP_DELAY_MIN, ANIM_MAX_IDEAL_FRAMES_DEFAULT, ANIM_MAX_IDEAL_FRAMES_MIN, ANIM_MAX_IDEAL_FRAMES_MAX, ANIMATION_OPTION_KEYS, COLOR_SCALE_SELF_CLAMP_PCT_DEFAULT, COLOR_SCALE_SELF_CLAMP_PCT_MIN, COLOR_SCALE_SELF_CLAMP_PCT_MAX, FLIP_MODE_DEFAULT, FLIP_INTERVAL_MIN_MS, FLIP_INTERVAL_MAX_MS, FLIP_DIRECTION_DEFAULT, APPROXIMATE_POSITIONS_DEFAULT, VALUE_AXIS_BASELINE_DEFAULT, SEASONAL_MARKERS_DEFAULT, MAX_MAP_POINTS_DEFAULT, type GeoPointPrecision, type GeoMapKind, type TimelineStyle, type FlipMode, type FlipDirection, type ApproximatePositions, type ValueAxisBaseline, type SeasonalMarkers, type ColorScaleScope, type RenderOptions, type ViewStateProvider, type ChartControlChange, type XfilterRefreshDetail, } from "./contract";
|
|
1
|
+
export { HOST_CONTRACT_VERSION, GEO_POINT_PRECISIONS, MARK_CLASS, LEGEND_MARK_CLASS, AXIS_FILTER_CLASS, ROW_IDX_ATTR, LIFT_SELECTED_CLASS, CONTROL_CLASS, NO_ROW_MARKS_ATTR, SELECTION_RULE_ATTR, SELECTION_RULE_CLICKED_MARKS, MARK_KEY_ATTR, CONTAINER_SLOT_CLICKED_MARKS, SNAPSHOT_SVG_ATTR, XFILTER_REFRESH_EVENT, CONTAINER_SLOT_ANIM_STOP, CONTAINER_SLOT_XF_CLEAR, CONTAINER_SLOT_INITIAL_XF_MARK, CONTAINER_SLOT_UI_STATE, CONTAINER_SLOT_SCROLL, VIEW_ONLY_UI_STATE_KEYS, withoutViewOnlyKeys, HOST_CONTAINER_CLASS, SELECTION_ACTIVE_CLASS, MARK_SELECTED_CLASS, ACTIVE_TICK_CLASS, DIM_OPACITY_VAR, DIM_OPACITY_DEFAULT, DIM_OPACITY_MIN, chartOwnsTimeline, periodTickSuppressesFeedback, ANIM_PLAY_SPEED_DEFAULT, ANIM_PLAY_SPEED_MIN, ANIM_PLAY_SPEED_MAX, ANIM_LOOP_DELAY_DEFAULT, ANIM_LOOP_DELAY_MIN, ANIM_MAX_IDEAL_FRAMES_DEFAULT, ANIM_MAX_IDEAL_FRAMES_MIN, ANIM_MAX_IDEAL_FRAMES_MAX, ANIMATION_OPTION_KEYS, COLOR_SCALE_SELF_CLAMP_PCT_DEFAULT, COLOR_SCALE_SELF_CLAMP_PCT_MIN, COLOR_SCALE_SELF_CLAMP_PCT_MAX, FLIP_MODE_DEFAULT, FLIP_INTERVAL_MIN_MS, FLIP_INTERVAL_MAX_MS, FLIP_DIRECTION_DEFAULT, APPROXIMATE_POSITIONS_DEFAULT, VALUE_AXIS_BASELINE_DEFAULT, SEASONAL_MARKERS_DEFAULT, MAX_MAP_POINTS_DEFAULT, type GeoPointPrecision, type GeoMapKind, type TimelineStyle, type FlipMode, type FlipDirection, type ApproximatePositions, type ValueAxisBaseline, type SeasonalMarkers, type ColorScaleScope, type RenderOptions, type ViewStateProvider, type ChartControlChange, type XfilterRefreshDetail, } from "./contract";
|
|
2
2
|
export { resolveOptions, type ResolveOptionsInput } from "./defaults";
|
|
3
3
|
export { OPTIONS_VOCABULARY, LIVE_OPTION_KEYS, MAX_MAP_POINTS_MIN, MAX_MAP_POINTS_MAX, LIMIT_COUNT_MAX, wireLimitCount, codeReadsOption, type OptionVocabularyEntry, type OptionTiming, type OptionWire, type OptionKey, } from "./optionsVocabulary";
|
|
4
4
|
export { loadGeo, geoFromCache, registerGeo, registerGeoAsset, geoAssetFor, clearGeoCache, type GeoAssetName, } from "./geoLazy";
|
|
@@ -42,6 +42,8 @@ export { SCROLL_SLACK_PX, MAX_FRAME_GROW_FACTOR, PHANTOM_FRACTION, FIT_CONTENT_S
|
|
|
42
42
|
export { fitRenderedChart, fitReadingFor, measureContainerBoxes, svgInkReach, ctmScaleOf, type FitReading, type InkReach, type FitRenderedChartOptions, type FitRenderedChartResult, } from "./fitDom";
|
|
43
43
|
export { AXIS_PIN_MIN_LABELS, AXIS_PIN_BAND_PAD_PX, AXIS_PIN_MAX_BAND_FRACTION, AXIS_PIN_TRACK_REACH_PX, isHorizontalLabelRow, labelBand, planAxisPin, axisPinPlacement, type LabelRowBox, type AxisBand, type AxisPinCandidate, type AxisPinPlan, type AxisPinEdge, } from "./fit";
|
|
44
44
|
export { pinScrolledAxis, unpinScrolledAxis, type AxisPinReport } from "./fitDom";
|
|
45
|
+
export { planScrollRestore, type ScrollMemory, type ScrollMetrics } from "./fit";
|
|
46
|
+
export { rememberScroll, takeScroll } from "./fitDom";
|
|
45
47
|
export { MIN_DELTA_E, pickDistinctColorFromSeed, buildPalette, buildPaletteFromSeed, orderMostDistinct, LEGIBLE_LIGHTNESS, type PaletteResult, type SeedForSlot, type PaletteOptions, } from "./palette";
|
|
46
48
|
export { deltaEHex } from "./deltaE";
|
|
47
49
|
export { resolveAutoColorScale, autoRampMinStep, autoRampCanvas, AUTO_RAMP_CLASSES, AUTO_RAMP_DRAWN_OPACITY, AUTO_RAMP_MIN_STEP_DELTA_E, type AutoColorScale, type AutoColorScaleInput } from "./autoRamp";
|
package/dist/types/react.d.ts
CHANGED
|
@@ -46,8 +46,17 @@ export interface BicChartProps {
|
|
|
46
46
|
* themed page is not white, and readability is measured against it. See createChartHost.
|
|
47
47
|
*/
|
|
48
48
|
labelContrast?: ChartHostConfig["labelContrast"];
|
|
49
|
+
/**
|
|
50
|
+
* KEEP THE READER'S SCROLL when the same chart repaints (new data, new options, a rebuild).
|
|
51
|
+
* Default on; a different chart opens at the top. Pass `false` for a page that manages the
|
|
52
|
+
* chart's scrolling itself. Host config: changing it rebuilds the host. See createChartHost.
|
|
53
|
+
*/
|
|
54
|
+
restoreScroll?: ChartHostConfig["restoreScroll"];
|
|
49
55
|
/** What the label-contrast pass did after each render - counts, for a page that logs. */
|
|
50
56
|
onLabelContrast?: ChartHostConfig["onLabelContrast"];
|
|
57
|
+
/** What the selection-glyph pass did after each paint, when `options.selectionGlyph` is set - counts, for a page
|
|
58
|
+
* that logs. The glyph itself, the dim level and the suppression fact ride the `options` prop. */
|
|
59
|
+
onSelectionGlyphs?: ChartHostConfig["onSelectionGlyphs"];
|
|
51
60
|
/**
|
|
52
61
|
* A LAYOUT PASS run after every render, after label contrast and before the fit - e.g.
|
|
53
62
|
* `createLegendFitPass()` from "@bicharts/chart-host/legend-fit", which slides a legend clear of
|
|
@@ -169,6 +169,18 @@ export declare function collectD3GlyphCenters(container: Element, baseRect: {
|
|
|
169
169
|
left: number;
|
|
170
170
|
top: number;
|
|
171
171
|
}, out: GlyphCenter[]): void;
|
|
172
|
+
/** Which selected marks get a glyph, for a host that draws its own layer: `shown` drops a mark before anything is
|
|
173
|
+
* measured against it (a mark the reader can't see), `at` drops one by where its glyph would go, in client
|
|
174
|
+
* coordinates (a mark panned or zoomed out of its plot). Either absent keeps every mark. */
|
|
175
|
+
export interface GlyphCenterFilter {
|
|
176
|
+
shown?(mark: Element): boolean;
|
|
177
|
+
at?(mark: Element, clientX: number, clientY: number): boolean;
|
|
178
|
+
}
|
|
179
|
+
/** collectD3GlyphCenters with a filter. Package-internal: the exported function keeps every mark, as it always has. */
|
|
180
|
+
export declare function collectGlyphCentersWhere(container: Element, baseRect: {
|
|
181
|
+
left: number;
|
|
182
|
+
top: number;
|
|
183
|
+
}, out: GlyphCenter[], filter?: GlyphCenterFilter): void;
|
|
172
184
|
/** The class every painted selection glyph carries. */
|
|
173
185
|
export declare const SELECTION_GLYPH_CLASS = "lch-sel-glyph";
|
|
174
186
|
/** Removes every glyph (every child) from the overlay. */
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bicharts/chart-host",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.90",
|
|
4
4
|
"description": "Run a BIC-generated D3 chart in any web host: compiles the generated render() function, applies the shared option defaults, resolves mark clicks (through tooltip overlays), owns the selection affordance, and translates row indices between cross-filtered charts. The same contract the BIC Power BI visual implements, minus Power BI. React bindings at @bicharts/chart-host/react.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"type": "module",
|