@bicharts/chart-host 0.6.50 → 0.6.52
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/{chunk-P4FOCNAX.mjs → chunk-TOKJTZNS.mjs} +167 -8
- package/dist/index.mjs +5 -1
- package/dist/react.mjs +18 -2
- package/dist/types/annotations.d.ts +40 -0
- package/dist/types/host.d.ts +14 -0
- package/dist/types/index.d.ts +1 -0
- package/dist/types/react.d.ts +8 -0
- package/package.json +1 -1
|
@@ -3518,10 +3518,10 @@ function paintRoot(el, container) {
|
|
|
3518
3518
|
}
|
|
3519
3519
|
return root;
|
|
3520
3520
|
}
|
|
3521
|
-
function drawnBeneath(shape,
|
|
3521
|
+
function drawnBeneath(shape, text2, textRoot) {
|
|
3522
3522
|
if (!shape.root || shape.root !== textRoot) return true;
|
|
3523
3523
|
if (typeof shape.el.compareDocumentPosition !== "function") return true;
|
|
3524
|
-
return (shape.el.compareDocumentPosition(
|
|
3524
|
+
return (shape.el.compareDocumentPosition(text2) & DOC_POSITION_FOLLOWING) !== 0;
|
|
3525
3525
|
}
|
|
3526
3526
|
function sampleBackgrounds(shapes, pts, pageRGB, effAlpha) {
|
|
3527
3527
|
if (pts.length === 0 || shapes.length === 0) return null;
|
|
@@ -3797,13 +3797,13 @@ function applyLabelContrast(container, opts = {}) {
|
|
|
3797
3797
|
}
|
|
3798
3798
|
|
|
3799
3799
|
// src/invalidSentinel.ts
|
|
3800
|
-
function isInvalidSentinelError(
|
|
3801
|
-
if (!
|
|
3802
|
-
return /\bINVALID\s*:/.test(
|
|
3800
|
+
function isInvalidSentinelError(text2) {
|
|
3801
|
+
if (!text2) return false;
|
|
3802
|
+
return /\bINVALID\s*:/.test(text2);
|
|
3803
3803
|
}
|
|
3804
|
-
function invalidSentinelReason(
|
|
3805
|
-
if (!
|
|
3806
|
-
const m4 = /\bINVALID\s*:\s*([^\r\n]*)/.exec(
|
|
3804
|
+
function invalidSentinelReason(text2, max = 240) {
|
|
3805
|
+
if (!text2) return "";
|
|
3806
|
+
const m4 = /\bINVALID\s*:\s*([^\r\n]*)/.exec(text2);
|
|
3807
3807
|
if (!m4) return "";
|
|
3808
3808
|
const reason = m4[1].trim();
|
|
3809
3809
|
const cap = Math.max(0, Math.floor(max));
|
|
@@ -3811,6 +3811,138 @@ function invalidSentinelReason(text, max = 240) {
|
|
|
3811
3811
|
return cap <= 3 ? reason.slice(0, cap) : reason.slice(0, cap - 3).trimEnd() + "...";
|
|
3812
3812
|
}
|
|
3813
3813
|
|
|
3814
|
+
// src/annotations.ts
|
|
3815
|
+
var ANNOTATION_LAYER_CLASS = "bic-annotations";
|
|
3816
|
+
var ANNOTATION_CLASS = "bic-annotation";
|
|
3817
|
+
var text = (v) => v == null ? "" : String(v).trim();
|
|
3818
|
+
var parseIdxs = (s2) => (s2 || "").split(",").map((x3) => parseInt(x3, 10)).filter((n) => Number.isFinite(n));
|
|
3819
|
+
function createAnnotationLayer(container, onClick) {
|
|
3820
|
+
let list = [];
|
|
3821
|
+
let report = { shown: 0, notShown: 0 };
|
|
3822
|
+
let last = null;
|
|
3823
|
+
const doc = container.ownerDocument;
|
|
3824
|
+
const win = doc.defaultView;
|
|
3825
|
+
let observer = null;
|
|
3826
|
+
let queued = false;
|
|
3827
|
+
const redrawSoon = () => {
|
|
3828
|
+
if (queued || !last) return;
|
|
3829
|
+
queued = true;
|
|
3830
|
+
const run = () => {
|
|
3831
|
+
queued = false;
|
|
3832
|
+
if (last) paint(last.data, last.theme);
|
|
3833
|
+
};
|
|
3834
|
+
if (win?.requestAnimationFrame) win.requestAnimationFrame(run);
|
|
3835
|
+
else setTimeout(run, 16);
|
|
3836
|
+
};
|
|
3837
|
+
const watch = (on) => {
|
|
3838
|
+
const MO = win?.MutationObserver;
|
|
3839
|
+
if (on && !observer && MO) {
|
|
3840
|
+
observer = new MO((records) => {
|
|
3841
|
+
if (records.some((r2) => !r2.target.closest?.(`.${ANNOTATION_LAYER_CLASS}`))) redrawSoon();
|
|
3842
|
+
});
|
|
3843
|
+
observer.observe(container, { subtree: true, attributes: true, attributeFilter: ["transform", "d", "cx", "cy", "x", "y", "points"] });
|
|
3844
|
+
} else if (!on && observer) {
|
|
3845
|
+
observer.disconnect();
|
|
3846
|
+
observer = null;
|
|
3847
|
+
}
|
|
3848
|
+
};
|
|
3849
|
+
function paint(data, theme) {
|
|
3850
|
+
let layer = container.querySelector(`:scope > .${ANNOTATION_LAYER_CLASS}`);
|
|
3851
|
+
if (!list.length) {
|
|
3852
|
+
layer?.remove();
|
|
3853
|
+
report = { shown: 0, notShown: 0 };
|
|
3854
|
+
return;
|
|
3855
|
+
}
|
|
3856
|
+
if (!layer) {
|
|
3857
|
+
layer = doc.createElement("div");
|
|
3858
|
+
layer.className = ANNOTATION_LAYER_CLASS;
|
|
3859
|
+
layer.setAttribute("aria-hidden", "false");
|
|
3860
|
+
Object.assign(layer.style, { position: "absolute", left: "0", top: "0", width: "0", height: "0", overflow: "visible", zIndex: "2" });
|
|
3861
|
+
if (win?.getComputedStyle(container).position === "static") container.style.position = "relative";
|
|
3862
|
+
container.appendChild(layer);
|
|
3863
|
+
}
|
|
3864
|
+
layer.textContent = "";
|
|
3865
|
+
const names = (data.columns || []).map((c2) => typeof c2 === "string" ? c2 : c2?.name);
|
|
3866
|
+
const marks = Array.from(container.querySelectorAll(`.${MARK_CLASS}[${ROW_IDX_ATTR}]`)).filter((m4) => !m4.closest(`.${ANNOTATION_LAYER_CLASS}`));
|
|
3867
|
+
const marksByRow = /* @__PURE__ */ new Map();
|
|
3868
|
+
for (const m4 of marks) for (const r2 of parseIdxs(m4.getAttribute(ROW_IDX_ATTR))) {
|
|
3869
|
+
const at = marksByRow.get(r2);
|
|
3870
|
+
if (at) at.push(m4);
|
|
3871
|
+
else marksByRow.set(r2, [m4]);
|
|
3872
|
+
}
|
|
3873
|
+
const origin = container.getBoundingClientRect();
|
|
3874
|
+
let shown = 0;
|
|
3875
|
+
for (const a3 of list) {
|
|
3876
|
+
const pairs = (a3.where ? Object.entries(a3.where) : a3.column != null ? [[a3.column, a3.value]] : []).map(([c2, v]) => [names.indexOf(c2), text(v)]);
|
|
3877
|
+
const want = pairs.map((p4) => p4[1]).join(" / ");
|
|
3878
|
+
const hits = /* @__PURE__ */ new Set();
|
|
3879
|
+
if (pairs.length && pairs.every((p4) => p4[0] >= 0)) (data.rows || []).forEach((row, r2) => {
|
|
3880
|
+
if (pairs.every(([ci, v]) => text(row?.[ci]) === v)) for (const m4 of marksByRow.get(r2) ?? []) hits.add(m4);
|
|
3881
|
+
});
|
|
3882
|
+
if (!hits.size) continue;
|
|
3883
|
+
shown++;
|
|
3884
|
+
let best = null;
|
|
3885
|
+
for (const m4 of hits) {
|
|
3886
|
+
const b4 = m4.getBoundingClientRect();
|
|
3887
|
+
if (!best || b4.width * b4.height > best.width * best.height) best = b4;
|
|
3888
|
+
}
|
|
3889
|
+
const badge = doc.createElement("div");
|
|
3890
|
+
badge.className = ANNOTATION_CLASS;
|
|
3891
|
+
badge.textContent = a3.label ?? "\u2022";
|
|
3892
|
+
if (a3.title) badge.setAttribute("title", a3.title);
|
|
3893
|
+
badge.setAttribute("role", "button");
|
|
3894
|
+
badge.setAttribute("aria-label", a3.title ? `Note: ${a3.title}` : `Note on ${want}`);
|
|
3895
|
+
const laidOut = !!best && best.width > 0 && best.height > 0;
|
|
3896
|
+
Object.assign(badge.style, {
|
|
3897
|
+
position: "absolute",
|
|
3898
|
+
left: `${Math.round(laidOut ? best.left - origin.left + best.width / 2 : 0)}px`,
|
|
3899
|
+
top: `${Math.round(laidOut ? best.top - origin.top + best.height / 2 : 0)}px`,
|
|
3900
|
+
transform: "translate(-50%, -50%)",
|
|
3901
|
+
minWidth: "16px",
|
|
3902
|
+
height: "16px",
|
|
3903
|
+
padding: "0 4px",
|
|
3904
|
+
boxSizing: "border-box",
|
|
3905
|
+
borderRadius: "8px",
|
|
3906
|
+
font: "600 10px/16px system-ui, sans-serif",
|
|
3907
|
+
textAlign: "center",
|
|
3908
|
+
color: theme.bg || "#ffffff",
|
|
3909
|
+
background: theme.accent || theme.fg || "#0f6cbd",
|
|
3910
|
+
boxShadow: `0 0 0 1.5px ${theme.bg || "#ffffff"}`,
|
|
3911
|
+
cursor: onClick ? "pointer" : "default",
|
|
3912
|
+
// Never pointer-events (a host failsafe turns it back on); visibility hides a badge whose mark
|
|
3913
|
+
// has no box yet.
|
|
3914
|
+
visibility: laidOut ? "visible" : "hidden"
|
|
3915
|
+
});
|
|
3916
|
+
badge.addEventListener("click", (e) => {
|
|
3917
|
+
e.stopPropagation();
|
|
3918
|
+
onClick?.(a3);
|
|
3919
|
+
});
|
|
3920
|
+
layer.appendChild(badge);
|
|
3921
|
+
}
|
|
3922
|
+
report = { shown, notShown: list.length - shown };
|
|
3923
|
+
}
|
|
3924
|
+
return {
|
|
3925
|
+
set(next) {
|
|
3926
|
+
list = Array.isArray(next) ? next.slice() : [];
|
|
3927
|
+
watch(list.length > 0);
|
|
3928
|
+
if (last) paint(last.data, last.theme);
|
|
3929
|
+
},
|
|
3930
|
+
draw(data, theme) {
|
|
3931
|
+
last = { data, theme };
|
|
3932
|
+
paint(data, theme);
|
|
3933
|
+
},
|
|
3934
|
+
get report() {
|
|
3935
|
+
return report;
|
|
3936
|
+
},
|
|
3937
|
+
destroy() {
|
|
3938
|
+
watch(false);
|
|
3939
|
+
list = [];
|
|
3940
|
+
last = null;
|
|
3941
|
+
container.querySelector(`:scope > .${ANNOTATION_LAYER_CLASS}`)?.remove();
|
|
3942
|
+
}
|
|
3943
|
+
};
|
|
3944
|
+
}
|
|
3945
|
+
|
|
3814
3946
|
// src/host.ts
|
|
3815
3947
|
function sessionViewStateProvider(container) {
|
|
3816
3948
|
const holder = container;
|
|
@@ -3971,6 +4103,16 @@ function createChartHost(container, config) {
|
|
|
3971
4103
|
let warnedGeo = false;
|
|
3972
4104
|
let warnedBlank = false;
|
|
3973
4105
|
let renderSeq = 0;
|
|
4106
|
+
const annotationLayer = createAnnotationLayer(container, (a3) => config.onAnnotationClick?.(a3));
|
|
4107
|
+
const drawAnnotations = () => annotationLayer.draw(
|
|
4108
|
+
{ columns: data.columns, rows: data.rows },
|
|
4109
|
+
{
|
|
4110
|
+
fg: resolved.themeFg,
|
|
4111
|
+
accent: resolved.themeAccent,
|
|
4112
|
+
bg: resolved.backgroundColor ?? resolved.themeBg
|
|
4113
|
+
}
|
|
4114
|
+
);
|
|
4115
|
+
annotationLayer.set(config.annotations ?? []);
|
|
3974
4116
|
let renderedPromise = Promise.resolve();
|
|
3975
4117
|
const settle = (p4) => {
|
|
3976
4118
|
renderedPromise = p4;
|
|
@@ -4192,6 +4334,10 @@ function createChartHost(container, config) {
|
|
|
4192
4334
|
} catch {
|
|
4193
4335
|
}
|
|
4194
4336
|
}
|
|
4337
|
+
try {
|
|
4338
|
+
drawAnnotations();
|
|
4339
|
+
} catch {
|
|
4340
|
+
}
|
|
4195
4341
|
};
|
|
4196
4342
|
const renderFailure = (err) => {
|
|
4197
4343
|
const message = String(err?.message ?? err ?? "");
|
|
@@ -4290,6 +4436,16 @@ function createChartHost(container, config) {
|
|
|
4290
4436
|
get options() {
|
|
4291
4437
|
return resolved;
|
|
4292
4438
|
},
|
|
4439
|
+
setAnnotations(list) {
|
|
4440
|
+
annotationLayer.set(list);
|
|
4441
|
+
if (!destroyed) try {
|
|
4442
|
+
drawAnnotations();
|
|
4443
|
+
} catch {
|
|
4444
|
+
}
|
|
4445
|
+
},
|
|
4446
|
+
get annotationReport() {
|
|
4447
|
+
return annotationLayer.report;
|
|
4448
|
+
},
|
|
4293
4449
|
// A GETTER, not a captured value: `rendered` names the LATEST render, so a host that
|
|
4294
4450
|
// read it once would otherwise hold the promise of a draw long since replaced.
|
|
4295
4451
|
get rendered() {
|
|
@@ -4328,6 +4484,7 @@ function createChartHost(container, config) {
|
|
|
4328
4484
|
container.removeEventListener(XFILTER_REFRESH_EVENT, onXf);
|
|
4329
4485
|
container.removeEventListener("click", onClick);
|
|
4330
4486
|
subs.clear();
|
|
4487
|
+
annotationLayer.destroy();
|
|
4331
4488
|
unpinScrolledAxis(container);
|
|
4332
4489
|
container.innerHTML = "";
|
|
4333
4490
|
}
|
|
@@ -4629,6 +4786,8 @@ export {
|
|
|
4629
4786
|
applyLabelContrast,
|
|
4630
4787
|
isInvalidSentinelError,
|
|
4631
4788
|
invalidSentinelReason,
|
|
4789
|
+
ANNOTATION_LAYER_CLASS,
|
|
4790
|
+
ANNOTATION_CLASS,
|
|
4632
4791
|
sessionViewStateProvider,
|
|
4633
4792
|
noopViewStateProvider,
|
|
4634
4793
|
assembleD3,
|
package/dist/index.mjs
CHANGED
|
@@ -10,6 +10,8 @@ import {
|
|
|
10
10
|
ANIM_PLAY_SPEED_DEFAULT,
|
|
11
11
|
ANIM_PLAY_SPEED_MAX,
|
|
12
12
|
ANIM_PLAY_SPEED_MIN,
|
|
13
|
+
ANNOTATION_CLASS,
|
|
14
|
+
ANNOTATION_LAYER_CLASS,
|
|
13
15
|
APPROXIMATE_POSITIONS_DEFAULT,
|
|
14
16
|
AUTO_RAMP_CLASSES,
|
|
15
17
|
AUTO_RAMP_DRAWN_OPACITY,
|
|
@@ -163,7 +165,7 @@ import {
|
|
|
163
165
|
unpinScrolledAxis,
|
|
164
166
|
valuePlacementFlag,
|
|
165
167
|
withoutViewOnlyKeys
|
|
166
|
-
} from "./chunk-
|
|
168
|
+
} from "./chunk-TOKJTZNS.mjs";
|
|
167
169
|
import "./chunk-A2GMXZP7.mjs";
|
|
168
170
|
import "./chunk-GHODWOAL.mjs";
|
|
169
171
|
|
|
@@ -2789,6 +2791,8 @@ export {
|
|
|
2789
2791
|
ANIM_PLAY_SPEED_DEFAULT,
|
|
2790
2792
|
ANIM_PLAY_SPEED_MAX,
|
|
2791
2793
|
ANIM_PLAY_SPEED_MIN,
|
|
2794
|
+
ANNOTATION_CLASS,
|
|
2795
|
+
ANNOTATION_LAYER_CLASS,
|
|
2792
2796
|
APPROXIMATE_POSITIONS_DEFAULT,
|
|
2793
2797
|
AUTO_RAMP_CLASSES,
|
|
2794
2798
|
AUTO_RAMP_DRAWN_OPACITY,
|
package/dist/react.mjs
CHANGED
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
loadGeo,
|
|
8
8
|
syncMemberSelection,
|
|
9
9
|
toSourceRows
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-TOKJTZNS.mjs";
|
|
11
11
|
import "./chunk-A2GMXZP7.mjs";
|
|
12
12
|
import "./chunk-GHODWOAL.mjs";
|
|
13
13
|
|
|
@@ -53,6 +53,8 @@ function BicChart(props) {
|
|
|
53
53
|
filteredBy,
|
|
54
54
|
respondsWith,
|
|
55
55
|
onSelect,
|
|
56
|
+
annotations,
|
|
57
|
+
onAnnotationClick,
|
|
56
58
|
className,
|
|
57
59
|
style
|
|
58
60
|
} = props;
|
|
@@ -78,6 +80,11 @@ function BicChart(props) {
|
|
|
78
80
|
onLabelContrastRef.current = onLabelContrast;
|
|
79
81
|
const onInvalidSentinelRef = useRef(onInvalidSentinel);
|
|
80
82
|
onInvalidSentinelRef.current = onInvalidSentinel;
|
|
83
|
+
const onAnnotationClickRef = useRef(onAnnotationClick);
|
|
84
|
+
onAnnotationClickRef.current = onAnnotationClick;
|
|
85
|
+
const annKey = useMemo(() => JSON.stringify(annotations ?? []), [annotations]);
|
|
86
|
+
const annotationsRef = useRef(annotations);
|
|
87
|
+
annotationsRef.current = annotations;
|
|
81
88
|
const [geoTick, setGeoTick] = useState(0);
|
|
82
89
|
useEffect(() => {
|
|
83
90
|
if (!geoKind || geoFromCache(geoKind)) return;
|
|
@@ -112,9 +119,12 @@ function BicChart(props) {
|
|
|
112
119
|
// newest prop wins without a rebuild.
|
|
113
120
|
get onInvalidSentinel() {
|
|
114
121
|
return onInvalidSentinelRef.current ? (info) => onInvalidSentinelRef.current?.(info) : void 0;
|
|
115
|
-
}
|
|
122
|
+
},
|
|
123
|
+
annotations: annotationsRef.current ?? [],
|
|
124
|
+
onAnnotationClick: (a) => onAnnotationClickRef.current?.(a)
|
|
116
125
|
});
|
|
117
126
|
hostRef.current = host;
|
|
127
|
+
builtAnnKeyRef.current = annKey;
|
|
118
128
|
const off = host.selection.onChange((payloadIdxs, source) => {
|
|
119
129
|
if (source === "host") return;
|
|
120
130
|
const sourceIdxs = toSourceRows(rowMapRef.current, payloadIdxs);
|
|
@@ -135,6 +145,12 @@ function BicChart(props) {
|
|
|
135
145
|
builtWithRef.current = { ...builtWithRef.current, optKey };
|
|
136
146
|
hostRef.current.setOptions(options);
|
|
137
147
|
}, [optKey]);
|
|
148
|
+
const builtAnnKeyRef = useRef(null);
|
|
149
|
+
useEffect(() => {
|
|
150
|
+
if (!hostRef.current || builtAnnKeyRef.current === annKey) return;
|
|
151
|
+
builtAnnKeyRef.current = annKey;
|
|
152
|
+
hostRef.current.setAnnotations(annotationsRef.current ?? []);
|
|
153
|
+
}, [annKey]);
|
|
138
154
|
useEffect(() => {
|
|
139
155
|
if (!hostRef.current || !data) return;
|
|
140
156
|
if (builtWithRef.current?.data === data) return;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
export interface MarkAnnotation {
|
|
2
|
+
/** The column holding the key (with `value`). */
|
|
3
|
+
column?: string;
|
|
4
|
+
/** The key's value; matched as text, trimmed, so a number column and a string key agree. */
|
|
5
|
+
value?: string | number;
|
|
6
|
+
/**
|
|
7
|
+
* A key over several columns - a route by both of its ends, `{ Origin: "BRA", Dest: "CHL" }` - so no key
|
|
8
|
+
* column has to be added to the query or the chart. Every named column must match. Used instead of column/value.
|
|
9
|
+
*/
|
|
10
|
+
where?: Record<string, string | number>;
|
|
11
|
+
/** Badge text (a count, a letter). Default: a dot. */
|
|
12
|
+
label?: string;
|
|
13
|
+
/** Tooltip text - the note, or a summary of several. */
|
|
14
|
+
title?: string;
|
|
15
|
+
/** Anything the host wants back on click. */
|
|
16
|
+
id?: string;
|
|
17
|
+
}
|
|
18
|
+
export interface AnnotationReport {
|
|
19
|
+
/** Annotations drawn on a mark. */
|
|
20
|
+
shown: number;
|
|
21
|
+
/** Annotations with no mark in this render (filtered out, off the map, no such key). */
|
|
22
|
+
notShown: number;
|
|
23
|
+
}
|
|
24
|
+
export declare const ANNOTATION_LAYER_CLASS = "bic-annotations";
|
|
25
|
+
export declare const ANNOTATION_CLASS = "bic-annotation";
|
|
26
|
+
export interface AnnotationLayer {
|
|
27
|
+
set(list: MarkAnnotation[]): void;
|
|
28
|
+
/** Redraw against the container's current marks and the given data. */
|
|
29
|
+
draw(data: {
|
|
30
|
+
columns: any[];
|
|
31
|
+
rows: any[][];
|
|
32
|
+
}, theme: {
|
|
33
|
+
fg?: string;
|
|
34
|
+
accent?: string;
|
|
35
|
+
bg?: string;
|
|
36
|
+
}): void;
|
|
37
|
+
readonly report: AnnotationReport;
|
|
38
|
+
destroy(): void;
|
|
39
|
+
}
|
|
40
|
+
export declare function createAnnotationLayer(container: HTMLElement, onClick?: (a: MarkAnnotation) => void): AnnotationLayer;
|
package/dist/types/host.d.ts
CHANGED
|
@@ -6,6 +6,7 @@ import { type ColourSpreadCensus } from "./colourSpread";
|
|
|
6
6
|
import { type ValuePlacementCensus } from "./valuePlacement";
|
|
7
7
|
import { type FitRenderedChartOptions, type FitRenderedChartResult } from "./fitDom";
|
|
8
8
|
import { type LabelContrastOptions, type LabelContrastReport } from "./labelContrastDom";
|
|
9
|
+
import { type MarkAnnotation, type AnnotationReport } from "./annotations";
|
|
9
10
|
export type RenderFn = (container: HTMLElement, data: any, options: RenderOptions) => void;
|
|
10
11
|
/**
|
|
11
12
|
* THE SESSION PROVIDER — what every host got hard-coded before contract 1.6.0, now named.
|
|
@@ -181,8 +182,21 @@ export interface ChartHostConfig {
|
|
|
181
182
|
reason: string;
|
|
182
183
|
message: string;
|
|
183
184
|
}) => void;
|
|
185
|
+
/**
|
|
186
|
+
* NOTES ON MARKS. Each annotation names a key - a value in a column of this chart's data, such as a
|
|
187
|
+
* country code - and the host draws a badge on that key's mark after every render, wherever a filter,
|
|
188
|
+
* a re-query or a zoom has put it. Keyed by value, never by row position. Change them with
|
|
189
|
+
* setAnnotations; none (the default) draws nothing.
|
|
190
|
+
*/
|
|
191
|
+
annotations?: MarkAnnotation[];
|
|
192
|
+
/** A badge was clicked. The mark beneath is not selected. */
|
|
193
|
+
onAnnotationClick?: (annotation: MarkAnnotation) => void;
|
|
184
194
|
}
|
|
185
195
|
export interface ChartHost {
|
|
196
|
+
/** Replace the notes drawn on marks (see ChartHostConfig.annotations); redraws them at once. */
|
|
197
|
+
setAnnotations(list: MarkAnnotation[]): void;
|
|
198
|
+
/** How many annotations the last draw placed on a mark, and how many had none in this render. */
|
|
199
|
+
readonly annotationReport: AnnotationReport;
|
|
186
200
|
render(): void;
|
|
187
201
|
/**
|
|
188
202
|
* THE LAST RENDER, SETTLED. render() stays synchronous — it returns nothing, exactly as it
|
package/dist/types/index.d.ts
CHANGED
|
@@ -8,6 +8,7 @@ export declare function registerCityTable(packed: string): void;
|
|
|
8
8
|
export { buildRenderPayload, type RenderPayload, type GeoPointBinding } from "./payload";
|
|
9
9
|
export { codeReadsDatesInLocalTime, vegaSpecReadsDatesInLocalTime } from "./dateCells";
|
|
10
10
|
export { createChartHost, compileRenderFn, stripEsmExports, requiredD3Plugins, explainRenderFailure, sessionViewStateProvider, noopViewStateProvider, assembleD3, D3_PLUGIN_PACKAGES, type ChartHost, type ChartHostConfig, type RenderFn } from "./host";
|
|
11
|
+
export { ANNOTATION_CLASS, ANNOTATION_LAYER_CLASS, type MarkAnnotation, type AnnotationReport } from "./annotations";
|
|
11
12
|
export { createChartGroup, toSourceRows, syncMemberSelection, type ChartGroup, type ChartGroupMember, type ChartGroupSelection, type ChartGroupChange, type ChartGroupMemberOptions, type ChartGroupSourceOptions, type ChartGroupPayload } from "./group";
|
|
12
13
|
export { createMarkResolver, isInsideControl, rowIdxsFromMark, nextSelection, collectD3GlyphCenters, clearSelectionGlyphs, paintSelectionGlyphs, SELECTION_GLYPH_CLASS, type MarkResolver, type MarkResolverEnv, type GlyphCenter, type SelectionGlyphStyle, type SelectionModifiers, } from "./selection";
|
|
13
14
|
export { planTrivialChart, compileTrivialSource, type TrivialPlan, type TrivialShapeKind } from "./trivial";
|
package/dist/types/react.d.ts
CHANGED
|
@@ -61,6 +61,14 @@ export interface BicChartProps {
|
|
|
61
61
|
respondsWith?: "filter" | "highlight";
|
|
62
62
|
/** Selection callback in SOURCE row indices (group) or payload indices (standalone). */
|
|
63
63
|
onSelect?: (rowIdxs: number[]) => void;
|
|
64
|
+
/**
|
|
65
|
+
* Notes on marks: a badge on each key's mark, redrawn after every render - e.g.
|
|
66
|
+
* `[{ column: "CountryCode", value: "USA", label: "2", title: "..." }]`. Keyed by a value in a column,
|
|
67
|
+
* never a row position, so a filter or a re-query never moves one.
|
|
68
|
+
*/
|
|
69
|
+
annotations?: ChartHostConfig["annotations"];
|
|
70
|
+
/** A badge was clicked (the mark beneath is not selected). */
|
|
71
|
+
onAnnotationClick?: ChartHostConfig["onAnnotationClick"];
|
|
64
72
|
className?: string;
|
|
65
73
|
style?: React.CSSProperties;
|
|
66
74
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bicharts/chart-host",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.52",
|
|
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",
|