@bicharts/chart-host 0.5.45 → 0.5.46
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-DZ5FNFID.mjs → chunk-FC3XJPVX.mjs} +231 -158
- package/dist/index.mjs +67 -12
- package/dist/react.mjs +1 -1
- package/dist/types/selectionCard.d.ts +39 -4
- package/package.json +1 -1
|
@@ -433,20 +433,20 @@ function A3(n) {
|
|
|
433
433
|
if (r && i && c3(r) !== i && (r = null), n.city !== void 0 && n.city !== null) {
|
|
434
434
|
let a2 = u(String(n.city)), s = O(a2), f = s ? F(s, n.mapKind) : null;
|
|
435
435
|
if (f && f.length) {
|
|
436
|
-
let d = n.state === void 0 || n.state === null ? "" : String(n.state).trim(), R = d ? u(d) : "", g = d ? Y(d) : null,
|
|
436
|
+
let d = n.state === void 0 || n.state === null ? "" : String(n.state).trim(), R = d ? u(d) : "", g = d ? Y(d) : null, S = [], m2 = -1;
|
|
437
437
|
for (let c of f) {
|
|
438
438
|
let l = c.row, A = 0;
|
|
439
439
|
if (d && l.a1 !== "") if (g && l.a1 === g || u(l.a1) === R) A++;
|
|
440
440
|
else continue;
|
|
441
441
|
if (i) if (T(l.cc) === i) A++;
|
|
442
442
|
else continue;
|
|
443
|
-
A > m2 ? (m2 = A,
|
|
443
|
+
A > m2 ? (m2 = A, S = [c]) : A === m2 && S.push(c);
|
|
444
444
|
}
|
|
445
|
-
|
|
445
|
+
S.some((c) => c.primary) && (S = S.filter((c) => c.primary));
|
|
446
446
|
let p2 = /* @__PURE__ */ new Map();
|
|
447
|
-
for (let c of
|
|
447
|
+
for (let c of S) p2.set(c.row.lon.toFixed(2) + "," + c.row.lat.toFixed(2), c.row);
|
|
448
448
|
if (p2.size === 1) {
|
|
449
|
-
let c =
|
|
449
|
+
let c = S[0].row;
|
|
450
450
|
return { lat: c.lat, lon: c.lon, precision: "city" };
|
|
451
451
|
}
|
|
452
452
|
if (p2.size > 1) return { ambiguous: true, matches: p2.size };
|
|
@@ -469,26 +469,26 @@ function A3(n) {
|
|
|
469
469
|
var G = { latlon: 0, city: 1, zip3: 2, state: 3, country: 4 };
|
|
470
470
|
var x = 8;
|
|
471
471
|
function y3(n, e) {
|
|
472
|
-
let t = new Array(n.length), o = new Array(n.length), i = new Array(n.length), r = /* @__PURE__ */ new Set(), a2 = [], s = /* @__PURE__ */ new Set(), f = [], d = /* @__PURE__ */ new Set(), R = [], g = { latlon: 0, city: 0, zip3: 0, state: 0, country: 0 },
|
|
472
|
+
let t = new Array(n.length), o = new Array(n.length), i = new Array(n.length), r = /* @__PURE__ */ new Set(), a2 = [], s = /* @__PURE__ */ new Set(), f = [], d = /* @__PURE__ */ new Set(), R = [], g = { latlon: 0, city: 0, zip3: 0, state: 0, country: 0 }, S = 0, m2 = 0, p2 = null;
|
|
473
473
|
for (let l = 0; l < n.length; ++l) {
|
|
474
|
-
let A = n[l],
|
|
475
|
-
if (S3(
|
|
474
|
+
let A = n[l], C = A3({ ...A, mapKind: e });
|
|
475
|
+
if (S3(C)) {
|
|
476
476
|
t[l] = null, o[l] = null, i[l] = null, m2++;
|
|
477
|
-
let
|
|
478
|
-
|
|
479
|
-
} else if (
|
|
480
|
-
if (t[l] =
|
|
481
|
-
let
|
|
482
|
-
|
|
477
|
+
let M2 = K(A);
|
|
478
|
+
M2 && !d.has(M2.toLowerCase()) && (d.add(M2.toLowerCase()), R.length < x && R.push(M2));
|
|
479
|
+
} else if (C) {
|
|
480
|
+
if (t[l] = C.lat, o[l] = C.lon, i[l] = C.precision, S++, g[C.precision]++, (p2 === null || G[C.precision] > G[p2]) && (p2 = C.precision), G[C.precision] > G.city) {
|
|
481
|
+
let M2 = K(A);
|
|
482
|
+
M2 && !s.has(M2.toLowerCase()) && (s.add(M2.toLowerCase()), f.length < x && f.push(M2));
|
|
483
483
|
}
|
|
484
484
|
} else {
|
|
485
485
|
t[l] = null, o[l] = null, i[l] = null;
|
|
486
|
-
let
|
|
487
|
-
|
|
486
|
+
let M2 = K(A);
|
|
487
|
+
M2 && !r.has(M2.toLowerCase()) && (r.add(M2.toLowerCase()), a2.push(M2));
|
|
488
488
|
}
|
|
489
489
|
}
|
|
490
490
|
let c = !n3() && n.some((l) => l.city !== null && l.city !== void 0 && String(l.city).trim() !== "");
|
|
491
|
-
return { lat: t, lon: o, precisions: i, precision: p2, precisionCounts: g, coarseExamples: f, unmatched: a2, ambiguousRows: m2, ambiguousExamples: R, matchedRows:
|
|
491
|
+
return { lat: t, lon: o, precisions: i, precision: p2, precisionCounts: g, coarseExamples: f, unmatched: a2, ambiguousRows: m2, ambiguousExamples: R, matchedRows: S, totalRows: n.length, ...c ? { cityTableMissing: true } : {} };
|
|
492
492
|
}
|
|
493
493
|
function K(n) {
|
|
494
494
|
let e = [n.city, n.state, n.zip, n.country].filter((t) => t != null && String(t).trim() !== "").map((t) => String(t).trim()).join(", ");
|
|
@@ -569,13 +569,13 @@ function wn(n) {
|
|
|
569
569
|
}
|
|
570
570
|
function Kn(n, s) {
|
|
571
571
|
let i = new Array(n.length), r = /* @__PURE__ */ new Set(), A = [], y2 = 0;
|
|
572
|
-
for (let
|
|
573
|
-
let
|
|
574
|
-
if (i[
|
|
572
|
+
for (let S = 0; S < n.length; ++S) {
|
|
573
|
+
let O2 = hn(n[S], s);
|
|
574
|
+
if (i[S] = O2, O2 !== null) y2++;
|
|
575
575
|
else {
|
|
576
|
-
let
|
|
577
|
-
if (
|
|
578
|
-
let d = String(
|
|
576
|
+
let C = n[S];
|
|
577
|
+
if (C != null) {
|
|
578
|
+
let d = String(C).trim();
|
|
579
579
|
if (d.length > 0) {
|
|
580
580
|
let g = d.toLowerCase();
|
|
581
581
|
r.has(g) || (r.add(g), A.push(d));
|
|
@@ -588,142 +588,211 @@ function Kn(n, s) {
|
|
|
588
588
|
|
|
589
589
|
// ../shape-core/dist/index.mjs
|
|
590
590
|
/*! @bicharts/shape-core — Apache-2.0. Bundled reference data: GeoNames (https://www.geonames.org/) CC BY 4.0; US Census/TIGER (public domain). Full text: NOTICE in this package. */
|
|
591
|
-
var
|
|
592
|
-
var
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
591
|
+
var W2 = ["rate", "ratio", "pct", "percent", "percentage", "rating", "share", "score", "index", "nps", "csat", "margin", "yield", "coverage", "utilization", "z[_-]?score", "average", "avg", "mean", "median", "stddev", "variance", "gpa", "percentile", "quantile", "efficiency", "accuracy", "probability", "multiplier", "coefficient", "correlation", "occupancy", "age", "bmi", "temperature", "density", "pressure", "humidity", "ph", "velocity", "speed", "elevation", "altitude", "latency", "throughput", "bandwidth", "iops"];
|
|
592
|
+
var X2 = ["pct", "percent", "percentage", "rate", "ratio", "rating", "share", "score", "index", "nps", "csat", "margin", "yield", "coverage", "utilization", "gpa", "percentile", "quantile", "bmi", "density", "pressure", "humidity", "velocity", "efficiency", "occupancy", "latency", "throughput", "bandwidth", "iops"];
|
|
593
|
+
var Y2 = ["latitude", "longitude"];
|
|
594
|
+
var J2 = ["latitude", "longitude"];
|
|
595
|
+
var Q2 = /^\s*(sum|count|count\s+distinct|distinct\s+count)\s+of\s+/i;
|
|
596
|
+
var Ut = /(?<=[a-z0-9])(?=[A-Z])|(?<=[A-Za-z])(?=[0-9])|(?<=[0-9])(?=[A-Za-z])/g;
|
|
597
|
+
var Zt = new RegExp("\\b(" + W2.join("|") + ")\\b|(" + X2.join("|") + ")$", "i");
|
|
598
|
+
var qt = new RegExp("\\b(" + Y2.join("|") + ")\\b|(" + J2.join("|") + ")$", "i");
|
|
599
|
+
function M(e) {
|
|
600
|
+
return e ? String(e).replace(Q2, "").trim() : "";
|
|
601
|
+
}
|
|
602
|
+
function tt(e) {
|
|
603
|
+
return !!e && Q2.test(String(e));
|
|
604
|
+
}
|
|
605
|
+
function jt(e) {
|
|
606
|
+
let t = M(e);
|
|
607
|
+
return t.length === 0 ? "" : t.replace(Ut, " ");
|
|
608
|
+
}
|
|
609
|
+
function et(e, t) {
|
|
610
|
+
return t ? e.test(jt(t)) || e.test(M(t)) : false;
|
|
611
|
+
}
|
|
612
|
+
function L2(e) {
|
|
613
|
+
return et(qt, e);
|
|
614
|
+
}
|
|
615
|
+
function nt(e) {
|
|
616
|
+
return et(Zt, e) || L2(e);
|
|
617
|
+
}
|
|
618
|
+
var it = /int|double|decimal|single|float|number|currency|money/i;
|
|
619
|
+
function Wt(e) {
|
|
620
|
+
let t = String(e?.valueNature ?? "").trim().toLowerCase();
|
|
621
|
+
return t === "categorical" ? "Categorical" : t === "ordinal" ? "Ordinal" : t === "continuous" || e?.isMeasure === true || it.test(String(e?.dataType ?? "")) ? "Continuous" : "Categorical";
|
|
622
|
+
}
|
|
623
|
+
function Xt(e) {
|
|
624
|
+
return e?.isMeasure === true || it.test(String(e?.dataType ?? ""));
|
|
625
|
+
}
|
|
626
|
+
function z2(e) {
|
|
627
|
+
let t = e ?? {}, i = Wt(t);
|
|
628
|
+
if (i !== "Continuous") return { nature: i, additivity: "unknown", basis: "role", suppressed: false };
|
|
629
|
+
if (L2(t.name)) return { nature: i, additivity: "positional", basis: "name", suppressed: true };
|
|
630
|
+
let r = String(t.additivity ?? "").trim().toLowerCase();
|
|
631
|
+
if (!(r === "additive" && tt(t.name))) {
|
|
632
|
+
if (r === "additive") return { nature: i, additivity: "additive", basis: "measured", suppressed: false };
|
|
633
|
+
if (r === "part_of_whole") return { nature: i, additivity: "part_of_whole", basis: "measured", suppressed: false };
|
|
634
|
+
if (r === "intensive_rate") return { nature: i, additivity: "intensive_rate", basis: "measured", suppressed: false };
|
|
602
635
|
}
|
|
603
|
-
return
|
|
604
|
-
}
|
|
605
|
-
function
|
|
606
|
-
let
|
|
607
|
-
if (
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
function E2(r) {
|
|
617
|
-
let n = P2(r);
|
|
618
|
-
if (n.length === 0) return 0;
|
|
619
|
-
let e = 0;
|
|
620
|
-
for (let s of n) N2(s) && e++;
|
|
621
|
-
return Math.round(e / n.length * 1e3) / 10;
|
|
622
|
-
}
|
|
623
|
-
function S(r) {
|
|
624
|
-
let n = P2(r);
|
|
625
|
-
if (n.length === 0) return 0;
|
|
626
|
-
let e = 0;
|
|
627
|
-
for (let s of n) Y(s) && e++;
|
|
628
|
-
return Math.round(e / n.length * 1e3) / 10;
|
|
629
|
-
}
|
|
630
|
-
function D2(r) {
|
|
631
|
-
let n = /* @__PURE__ */ new Set();
|
|
632
|
-
for (let e of r) {
|
|
633
|
-
if (e == null) continue;
|
|
634
|
-
let s = String(e).trim();
|
|
635
|
-
if (!V(u(s)) && !n.has(s) && (n.add(s), n.size >= j2)) break;
|
|
636
|
+
return t.discourageAggregationAcrossGroups === true ? { nature: i, additivity: "intensive_rate", basis: "host-flag", suppressed: false } : nt(t.name) ? { nature: i, additivity: "intensive_rate", basis: "name", suppressed: false } : { nature: i, additivity: "additive", basis: "default", suppressed: false };
|
|
637
|
+
}
|
|
638
|
+
function G2(e) {
|
|
639
|
+
let t = z2(e), i = e ?? {};
|
|
640
|
+
if (t.nature === "Categorical") return ["first", "distinctcount", "count"];
|
|
641
|
+
if (t.nature === "Ordinal") return Xt(i) ? ["median", "min", "max", "first", "distinctcount", "count"] : ["first", "distinctcount", "count"];
|
|
642
|
+
switch (t.additivity) {
|
|
643
|
+
case "positional":
|
|
644
|
+
return ["min", "max", "count", "distinctcount", "first"];
|
|
645
|
+
case "intensive_rate":
|
|
646
|
+
return ["average", "median", "min", "max", "count", "distinctcount", "first"];
|
|
647
|
+
default:
|
|
648
|
+
return ["sum", "average", "median", "min", "max", "count", "distinctcount", "first"];
|
|
636
649
|
}
|
|
637
|
-
return Array.from(n);
|
|
638
|
-
}
|
|
639
|
-
function O2(r) {
|
|
640
|
-
let n = D2(r);
|
|
641
|
-
if (n.length === 0) return 0;
|
|
642
|
-
let e = 0;
|
|
643
|
-
for (let s of n) Z(s).length > 0 && e++;
|
|
644
|
-
return Math.round(e / n.length * 1e3) / 10;
|
|
645
|
-
}
|
|
646
|
-
function Z2(r, n) {
|
|
647
|
-
return p(n, en) ? true : D2(r).some((e) => /^\d{5}(-\d{4})?$/.test(e.replace(/\.0+$/, "")));
|
|
648
|
-
}
|
|
649
|
-
function Gt(r, n) {
|
|
650
|
-
let e = P2(r);
|
|
651
|
-
if (e.length === 0) return 0;
|
|
652
|
-
let s = 0;
|
|
653
|
-
for (let l of e) p3(l, n) && s++;
|
|
654
|
-
return Math.round(s / e.length * 1e3) / 10;
|
|
655
|
-
}
|
|
656
|
-
function $2(r, n) {
|
|
657
|
-
let e = 0;
|
|
658
|
-
for (let s of P2(r)) n(s) && e++;
|
|
659
|
-
return e;
|
|
660
|
-
}
|
|
661
|
-
function _t(r, n) {
|
|
662
|
-
let e = 0;
|
|
663
|
-
for (let s of D2(r)) n(s) && e++;
|
|
664
|
-
return e;
|
|
665
650
|
}
|
|
666
|
-
function
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
651
|
+
function Yt(e) {
|
|
652
|
+
return G2(e)[0];
|
|
653
|
+
}
|
|
654
|
+
function Qt(e, t) {
|
|
655
|
+
if (t !== "sum" && t !== "count") return false;
|
|
656
|
+
if (t === "count") return true;
|
|
657
|
+
let i = z2(e);
|
|
658
|
+
return i.additivity === "additive" || i.additivity === "part_of_whole" || i.additivity === "unknown";
|
|
659
|
+
}
|
|
660
|
+
var F2 = 2;
|
|
661
|
+
var st = 400;
|
|
662
|
+
function D2(e) {
|
|
663
|
+
return !!E(e);
|
|
664
|
+
}
|
|
665
|
+
function v2(e) {
|
|
666
|
+
let t = /* @__PURE__ */ new Set();
|
|
667
|
+
for (let i of e) {
|
|
668
|
+
if (i == null) continue;
|
|
669
|
+
let r = u(String(i));
|
|
670
|
+
if (!V(r) && !t.has(r) && (t.add(r), t.size >= st)) break;
|
|
671
|
+
}
|
|
672
|
+
return Array.from(t);
|
|
673
|
+
}
|
|
674
|
+
function h2(e) {
|
|
675
|
+
let t = v2(e);
|
|
676
|
+
if (t.length === 0 || K2(e) < 95) return false;
|
|
677
|
+
let i = t.filter((u2) => D2(u2) && !Y(u2)).length, r = t.filter((u2) => !D2(u2) && !!Y(u2)).length;
|
|
678
|
+
return i >= 1 && i >= r;
|
|
679
|
+
}
|
|
680
|
+
function ot(e, t) {
|
|
681
|
+
if (!Y(e)) return false;
|
|
682
|
+
let i = E(e);
|
|
683
|
+
return i ? t === "world" ? true : s3.has(i) : false;
|
|
684
|
+
}
|
|
685
|
+
function K2(e) {
|
|
686
|
+
let t = v2(e);
|
|
687
|
+
if (t.length === 0) return 0;
|
|
688
|
+
let i = 0;
|
|
689
|
+
for (let r of t) D2(r) && i++;
|
|
690
|
+
return Math.round(i / t.length * 1e3) / 10;
|
|
691
|
+
}
|
|
692
|
+
function P2(e) {
|
|
693
|
+
let t = v2(e);
|
|
694
|
+
if (t.length === 0) return 0;
|
|
695
|
+
let i = 0;
|
|
696
|
+
for (let r of t) Y(r) && i++;
|
|
697
|
+
return Math.round(i / t.length * 1e3) / 10;
|
|
698
|
+
}
|
|
699
|
+
function H2(e) {
|
|
700
|
+
let t = /* @__PURE__ */ new Set();
|
|
701
|
+
for (let i of e) {
|
|
702
|
+
if (i == null) continue;
|
|
703
|
+
let r = String(i).trim();
|
|
704
|
+
if (!V(u(r)) && !t.has(r) && (t.add(r), t.size >= st)) break;
|
|
705
|
+
}
|
|
706
|
+
return Array.from(t);
|
|
707
|
+
}
|
|
708
|
+
function B2(e) {
|
|
709
|
+
let t = H2(e);
|
|
710
|
+
if (t.length === 0) return 0;
|
|
711
|
+
let i = 0;
|
|
712
|
+
for (let r of t) Z(r).length > 0 && i++;
|
|
713
|
+
return Math.round(i / t.length * 1e3) / 10;
|
|
714
|
+
}
|
|
715
|
+
function rt(e, t) {
|
|
716
|
+
return p(t, en) ? true : H2(e).some((i) => /^\d{5}(-\d{4})?$/.test(i.replace(/\.0+$/, "")));
|
|
717
|
+
}
|
|
718
|
+
function te(e, t) {
|
|
719
|
+
let i = v2(e);
|
|
720
|
+
if (i.length === 0) return 0;
|
|
721
|
+
let r = 0;
|
|
722
|
+
for (let u2 of i) p3(u2, t) && r++;
|
|
723
|
+
return Math.round(r / i.length * 1e3) / 10;
|
|
724
|
+
}
|
|
725
|
+
function $2(e, t) {
|
|
726
|
+
let i = 0;
|
|
727
|
+
for (let r of v2(e)) t(r) && i++;
|
|
728
|
+
return i;
|
|
729
|
+
}
|
|
730
|
+
function ee(e, t) {
|
|
731
|
+
let i = 0;
|
|
732
|
+
for (let r of H2(e)) t(r) && i++;
|
|
733
|
+
return i;
|
|
734
|
+
}
|
|
735
|
+
function ne(e, t, i, r) {
|
|
736
|
+
let u2 = [], c = [], o = {}, I2 = {}, R = new Set(e), l = (n) => t.map((s) => s[n]);
|
|
737
|
+
for (let n of ["city", "lat", "lon", "country"]) {
|
|
738
|
+
let s = i?.[n];
|
|
739
|
+
s && R.has(s) && (o[n] = s);
|
|
671
740
|
}
|
|
672
|
-
let
|
|
673
|
-
if (
|
|
674
|
-
let
|
|
675
|
-
|
|
741
|
+
let p2 = i?.zip;
|
|
742
|
+
if (p2 && R.has(p2)) {
|
|
743
|
+
let n = l(p2), s = B2(n);
|
|
744
|
+
s < 95 ? c.push(`zip=${p2} (only ${s}% of values read as ZIPs)`) : rt(n, p2) ? o.zip = p2 : c.push(`zip=${p2} (all values are 3-4 digits with nothing to say they are postal)`);
|
|
676
745
|
}
|
|
677
|
-
let
|
|
678
|
-
if (
|
|
679
|
-
let
|
|
680
|
-
|
|
746
|
+
let f = i?.state;
|
|
747
|
+
if (f && R.has(f)) {
|
|
748
|
+
let n = l(f), s = v2(n);
|
|
749
|
+
s.length > 0 && s.every((a2) => ot(a2, r)) ? c.push(`state=${f} (every value is "CA", which is both Canada and California)`) : h2(n) ? (c.push(`state=${f} (every value is a country, not a state)`), o.country || (o.country = f)) : P2(n) < 95 ? c.push(`state=${f} (only ${P2(n)}% of values are states/provinces)`) : o.state = f;
|
|
681
750
|
}
|
|
682
|
-
let
|
|
751
|
+
let m2 = new Set(Object.values(o).filter(Boolean)), x2 = e.filter((n) => !m2.has(n) && !n.startsWith("__"));
|
|
683
752
|
if (!o.state) {
|
|
684
|
-
let
|
|
685
|
-
for (let
|
|
686
|
-
let a2 =
|
|
687
|
-
if (
|
|
688
|
-
let
|
|
689
|
-
if (
|
|
690
|
-
let
|
|
691
|
-
|
|
753
|
+
let n = null;
|
|
754
|
+
for (let s of x2) {
|
|
755
|
+
let a2 = l(s);
|
|
756
|
+
if (h2(a2)) continue;
|
|
757
|
+
let d = P2(a2);
|
|
758
|
+
if (d < 95) continue;
|
|
759
|
+
let E2 = $2(a2, (C) => !!Y(C)), ut = $2(a2, (C) => !!Y(C) && !ot(C, r));
|
|
760
|
+
E2 < F2 && ut < 1 || (!n || d > n.pct) && (n = { name: s, pct: d });
|
|
692
761
|
}
|
|
693
|
-
|
|
762
|
+
n && (o.state = n.name, m2.add(n.name), u2.push(`state=${n.name} (${n.pct}% states/provinces)`));
|
|
694
763
|
}
|
|
695
|
-
if (!o.zip) for (let
|
|
696
|
-
if (
|
|
697
|
-
let
|
|
698
|
-
if (!(a2 < 95) &&
|
|
699
|
-
o.zip =
|
|
764
|
+
if (!o.zip) for (let n of x2) {
|
|
765
|
+
if (m2.has(n)) continue;
|
|
766
|
+
let s = l(n), a2 = B2(s);
|
|
767
|
+
if (!(a2 < 95) && rt(s, n) && !(ee(s, (d) => Z(d).length > 0) < F2)) {
|
|
768
|
+
o.zip = n, m2.add(n), u2.push(`zip=${n} (${a2}% ZIP codes)`);
|
|
700
769
|
break;
|
|
701
770
|
}
|
|
702
771
|
}
|
|
703
|
-
let
|
|
704
|
-
if (!
|
|
705
|
-
let
|
|
706
|
-
for (let
|
|
707
|
-
if (
|
|
708
|
-
let a2 =
|
|
709
|
-
(!
|
|
772
|
+
let A = o.country;
|
|
773
|
+
if (!A || !h2(l(A))) {
|
|
774
|
+
let n = null;
|
|
775
|
+
for (let s of x2) {
|
|
776
|
+
if (m2.has(s) || !h2(l(s))) continue;
|
|
777
|
+
let a2 = K2(l(s));
|
|
778
|
+
(!n || a2 > n.pct) && (n = { name: s, pct: a2 });
|
|
710
779
|
}
|
|
711
|
-
|
|
780
|
+
n && (A && (c.push(`country=${A} (only ${K2(l(A))}% of values are country identifiers; using ${n.name} instead)`), I2.country = A), o.country = n.name, m2.add(n.name), u2.push(`country=${n.name}`));
|
|
712
781
|
}
|
|
713
782
|
if (!o.city) {
|
|
714
|
-
let
|
|
715
|
-
for (let
|
|
716
|
-
if (
|
|
717
|
-
let a2 =
|
|
718
|
-
|
|
783
|
+
let n = null;
|
|
784
|
+
for (let s of x2) {
|
|
785
|
+
if (m2.has(s)) continue;
|
|
786
|
+
let a2 = l(s), d = te(a2, r);
|
|
787
|
+
d < m3 || $2(a2, (E2) => p3(E2, r)) < F2 || (!n || d > n.pct) && (n = { name: s, pct: d });
|
|
719
788
|
}
|
|
720
|
-
|
|
789
|
+
n && (o.city = n.name, u2.push(`city=${n.name} (${n.pct}% known cities)`));
|
|
721
790
|
}
|
|
722
|
-
let
|
|
723
|
-
let
|
|
724
|
-
return isFinite(
|
|
791
|
+
let V2 = o.country ? l(o.country) : [], N2 = !!o.country && h2(V2), at = N2 ? new Set(V2.map((n) => E(n == null ? null : String(n))).filter(Boolean)).size : 0, U2 = N2 && at >= 2, O2 = !!(o.lat && o.lon) && t.some((n) => {
|
|
792
|
+
let s = +String(n[o.lat] ?? "").trim(), a2 = +String(n[o.lon] ?? "").trim();
|
|
793
|
+
return isFinite(s) && isFinite(a2) && s >= -90 && s <= 90 && a2 >= -180 && a2 <= 180 && String(n[o.lat] ?? "").trim() !== "" && String(n[o.lon] ?? "").trim() !== "";
|
|
725
794
|
});
|
|
726
|
-
return o.lat && o.lon && !
|
|
795
|
+
return o.lat && o.lon && !O2 && c.push(`lat/lon=${o.lat}/${o.lon} (no row holds a usable coordinate pair)`), o.country && !U2 && !(o.city || o.state || o.zip || O2) && c.push(N2 ? `country=${o.country} (every row resolves to the same country - nothing to place apart)` : `country=${o.country} (values are not country identifiers)`), { bind: !!(o.city || o.state || o.zip || U2 || O2) ? o : null, backfilled: u2, refused: c, ...Object.keys(I2).length ? { labelFallback: I2 } : {} };
|
|
727
796
|
}
|
|
728
797
|
|
|
729
798
|
// src/payload.ts
|
|
@@ -738,7 +807,7 @@ function resolvePointChannel(cols, rowObjs, point) {
|
|
|
738
807
|
let labelCol;
|
|
739
808
|
if (bind) {
|
|
740
809
|
const dims = cols.filter((c) => !c.isMeasure).map((c) => c.name);
|
|
741
|
-
const res =
|
|
810
|
+
const res = ne(dims, rowObjs, bind, point?.mapKind);
|
|
742
811
|
bind = res.bind;
|
|
743
812
|
rolesBackfilled = res.backfilled;
|
|
744
813
|
rolesRefused = res.refused;
|
|
@@ -806,11 +875,11 @@ function buildRenderPayload(cols, rowObjs, geo, point, destination) {
|
|
|
806
875
|
const row = rowObjs[r];
|
|
807
876
|
const a2 = new Array(cols.length + extra);
|
|
808
877
|
for (let c = 0; c < cols.length; c++) {
|
|
809
|
-
const
|
|
810
|
-
if (
|
|
811
|
-
a2[c] =
|
|
878
|
+
const v3 = row[colNames[c]];
|
|
879
|
+
if (v3 instanceof Date) {
|
|
880
|
+
a2[c] = v3.toISOString();
|
|
812
881
|
} else {
|
|
813
|
-
a2[c] =
|
|
882
|
+
a2[c] = v3 ?? null;
|
|
814
883
|
}
|
|
815
884
|
}
|
|
816
885
|
let k2 = cols.length;
|
|
@@ -862,8 +931,8 @@ function buildRenderPayload(cols, rowObjs, geo, point, destination) {
|
|
|
862
931
|
function createMarkResolver(env) {
|
|
863
932
|
const { root, doc, log } = env;
|
|
864
933
|
const isElement = (t) => {
|
|
865
|
-
const
|
|
866
|
-
if (
|
|
934
|
+
const E2 = doc?.defaultView?.Element ?? globalThis.Element;
|
|
935
|
+
if (E2 && t instanceof E2) return true;
|
|
867
936
|
return !!t && typeof t.closest === "function" && typeof t.getAttribute === "function";
|
|
868
937
|
};
|
|
869
938
|
const viewStyle = (n) => {
|
|
@@ -883,14 +952,14 @@ function createMarkResolver(env) {
|
|
|
883
952
|
return s === "transparent" || s === "none" || so <= 0.01;
|
|
884
953
|
};
|
|
885
954
|
const distToPathCenterline = (el, x2, y2) => {
|
|
886
|
-
const
|
|
887
|
-
if (!(
|
|
955
|
+
const L4 = el.getTotalLength();
|
|
956
|
+
if (!(L4 > 0)) return Number.MAX_VALUE;
|
|
888
957
|
const m2 = el.getScreenCTM();
|
|
889
958
|
if (!m2) return Number.MAX_VALUE;
|
|
890
959
|
let best = Number.MAX_VALUE;
|
|
891
|
-
const
|
|
892
|
-
for (let i = 0; i <=
|
|
893
|
-
const pt = el.getPointAtLength(
|
|
960
|
+
const N2 = 64;
|
|
961
|
+
for (let i = 0; i <= N2; i++) {
|
|
962
|
+
const pt = el.getPointAtLength(L4 * i / N2);
|
|
894
963
|
const dx = m2.a * pt.x + m2.c * pt.y + m2.e - x2;
|
|
895
964
|
const dy = m2.b * pt.x + m2.d * pt.y + m2.f - y2;
|
|
896
965
|
const d = dx * dx + dy * dy;
|
|
@@ -1194,7 +1263,7 @@ function createChartHost(container, config) {
|
|
|
1194
1263
|
let data = config.data;
|
|
1195
1264
|
{
|
|
1196
1265
|
const stamped = config.data?.meta?.hostContract;
|
|
1197
|
-
const major = (
|
|
1266
|
+
const major = (v3) => (v3 || "").split(".")[0];
|
|
1198
1267
|
if (stamped && major(stamped) !== major(HOST_CONTRACT_VERSION)) {
|
|
1199
1268
|
try {
|
|
1200
1269
|
(win?.console ?? console)?.warn(
|
|
@@ -1230,9 +1299,9 @@ function createChartHost(container, config) {
|
|
|
1230
1299
|
const ensureAffordanceStyles = () => {
|
|
1231
1300
|
try {
|
|
1232
1301
|
if (!doc || doc.getElementById("bic-chart-host-affordances")) return;
|
|
1233
|
-
const
|
|
1234
|
-
|
|
1235
|
-
|
|
1302
|
+
const st2 = doc.createElement("style");
|
|
1303
|
+
st2.id = "bic-chart-host-affordances";
|
|
1304
|
+
st2.textContent = `
|
|
1236
1305
|
/* TYPOGRAPHY FIREWALL. Generated charts set font-size but almost never line-height or
|
|
1237
1306
|
letter-spacing, so they INHERIT whatever the host page cascades in. A page with
|
|
1238
1307
|
\`:root { font: 18px/145% }\` (the stock Vite template does exactly this) hands every
|
|
@@ -1270,7 +1339,7 @@ function createChartHost(container, config) {
|
|
|
1270
1339
|
font-weight: 700 !important;
|
|
1271
1340
|
text-decoration: underline !important;
|
|
1272
1341
|
}`;
|
|
1273
|
-
(doc.head || doc.documentElement)?.appendChild(
|
|
1342
|
+
(doc.head || doc.documentElement)?.appendChild(st2);
|
|
1274
1343
|
} catch {
|
|
1275
1344
|
}
|
|
1276
1345
|
};
|
|
@@ -1503,6 +1572,10 @@ export {
|
|
|
1503
1572
|
registerGeoAsset,
|
|
1504
1573
|
clearGeoCache,
|
|
1505
1574
|
L3,
|
|
1575
|
+
z2 as z,
|
|
1576
|
+
G2 as G,
|
|
1577
|
+
Yt,
|
|
1578
|
+
Qt,
|
|
1506
1579
|
buildRenderPayload,
|
|
1507
1580
|
createMarkResolver,
|
|
1508
1581
|
ensureCrossfilterHitTargets,
|
package/dist/index.mjs
CHANGED
|
@@ -20,6 +20,7 @@ import {
|
|
|
20
20
|
DIM_OPACITY_DEFAULT,
|
|
21
21
|
DIM_OPACITY_VAR,
|
|
22
22
|
FLIP_MODE_DEFAULT,
|
|
23
|
+
G,
|
|
23
24
|
GEO_POINT_PRECISIONS,
|
|
24
25
|
HOST_CONTAINER_CLASS,
|
|
25
26
|
HOST_CONTRACT_VERSION,
|
|
@@ -27,9 +28,11 @@ import {
|
|
|
27
28
|
LEGEND_MARK_CLASS,
|
|
28
29
|
MARK_CLASS,
|
|
29
30
|
MARK_SELECTED_CLASS,
|
|
31
|
+
Qt,
|
|
30
32
|
ROW_IDX_ATTR,
|
|
31
33
|
SELECTION_ACTIVE_CLASS,
|
|
32
34
|
XFILTER_REFRESH_EVENT,
|
|
35
|
+
Yt,
|
|
33
36
|
blankRenderFlag,
|
|
34
37
|
buildRenderPayload,
|
|
35
38
|
censusMarks,
|
|
@@ -49,8 +52,9 @@ import {
|
|
|
49
52
|
registerGeoAsset,
|
|
50
53
|
requiredD3Plugins,
|
|
51
54
|
resolveOptions,
|
|
52
|
-
stripEsmExports
|
|
53
|
-
|
|
55
|
+
stripEsmExports,
|
|
56
|
+
z
|
|
57
|
+
} from "./chunk-FC3XJPVX.mjs";
|
|
54
58
|
import "./chunk-A2GMXZP7.mjs";
|
|
55
59
|
|
|
56
60
|
// src/trivial.ts
|
|
@@ -625,9 +629,6 @@ function normaliseAggregation(raw) {
|
|
|
625
629
|
if (/^(distinctcount|dcount|countdistinct|uniques?)$/.test(s)) return "distinctcount";
|
|
626
630
|
return "sum";
|
|
627
631
|
}
|
|
628
|
-
function isAdditive(agg) {
|
|
629
|
-
return agg === "sum" || agg === "count";
|
|
630
|
-
}
|
|
631
632
|
function aggLabel(agg) {
|
|
632
633
|
switch (agg) {
|
|
633
634
|
case "average":
|
|
@@ -654,6 +655,20 @@ function isMeasureColumn(col) {
|
|
|
654
655
|
if (col.isMeasure === true) return true;
|
|
655
656
|
return NUMERIC_DATATYPE.test(String(col.dataType ?? ""));
|
|
656
657
|
}
|
|
658
|
+
function isRealColumn(col) {
|
|
659
|
+
return !!col && !isSynthetic(col.name);
|
|
660
|
+
}
|
|
661
|
+
function isSuppressed(col) {
|
|
662
|
+
return z(col).suppressed;
|
|
663
|
+
}
|
|
664
|
+
function resolveAgg(col, requested, auto) {
|
|
665
|
+
const fallback = () => {
|
|
666
|
+
const d = Yt(col);
|
|
667
|
+
return d === "first" ? "count" : d;
|
|
668
|
+
};
|
|
669
|
+
if (auto) return fallback();
|
|
670
|
+
return G(col).indexOf(requested) >= 0 ? requested : fallback();
|
|
671
|
+
}
|
|
657
672
|
function toNumber(v) {
|
|
658
673
|
if (v == null || v === "") return null;
|
|
659
674
|
const n = typeof v === "number" ? v : Number(v);
|
|
@@ -709,9 +724,11 @@ function computeSelectionCard(payload, selectedRowIdxs, opts = {}) {
|
|
|
709
724
|
if (pos != null && pos >= 0 && pos < rows.length) positions.push(pos);
|
|
710
725
|
}
|
|
711
726
|
if (!positions.length) return null;
|
|
727
|
+
const auto = String(opts.aggregation ?? "").trim().length === 0;
|
|
712
728
|
const agg = normaliseAggregation(opts.aggregation);
|
|
713
729
|
const maxMeasures = opts.maxMeasures ?? 4;
|
|
714
730
|
const maxHeaderValues = opts.maxHeaderValues ?? 3;
|
|
731
|
+
const maxDimensions = opts.maxDimensions ?? 2;
|
|
715
732
|
const dimIdx = columns.findIndex((c) => c && !isSynthetic(c.name) && !isMeasureColumn(c));
|
|
716
733
|
let header;
|
|
717
734
|
if (dimIdx >= 0) {
|
|
@@ -731,10 +748,20 @@ function computeSelectionCard(payload, selectedRowIdxs, opts = {}) {
|
|
|
731
748
|
header = `${positions.length} mark${positions.length === 1 ? "" : "s"}`;
|
|
732
749
|
}
|
|
733
750
|
const measureCols = [];
|
|
734
|
-
|
|
751
|
+
const suppressedColumns = [];
|
|
752
|
+
for (let c = 0; c < columns.length; c++) {
|
|
753
|
+
if (!isMeasureColumn(columns[c])) continue;
|
|
754
|
+
if (isSuppressed(columns[c])) {
|
|
755
|
+
suppressedColumns.push(String(columns[c]?.name ?? ""));
|
|
756
|
+
continue;
|
|
757
|
+
}
|
|
758
|
+
measureCols.push(c);
|
|
759
|
+
}
|
|
735
760
|
const shown = measureCols.slice(0, maxMeasures);
|
|
736
761
|
const lines = [];
|
|
737
762
|
for (const c of shown) {
|
|
763
|
+
const col = columns[c];
|
|
764
|
+
const colAgg = resolveAgg(col, agg, auto);
|
|
738
765
|
const selVals = [];
|
|
739
766
|
const selRaw = [];
|
|
740
767
|
for (const p of positions) {
|
|
@@ -742,9 +769,9 @@ function computeSelectionCard(payload, selectedRowIdxs, opts = {}) {
|
|
|
742
769
|
selRaw.push(rows[p]?.[c]);
|
|
743
770
|
if (n != null) selVals.push(n);
|
|
744
771
|
}
|
|
745
|
-
const value = reduce(selVals,
|
|
772
|
+
const value = reduce(selVals, colAgg, selRaw);
|
|
746
773
|
let sharePct = null;
|
|
747
|
-
if (
|
|
774
|
+
if (Qt(col, colAgg) && value != null) {
|
|
748
775
|
const allVals = [];
|
|
749
776
|
const allRaw = [];
|
|
750
777
|
for (let r = 0; r < rows.length; r++) {
|
|
@@ -752,21 +779,49 @@ function computeSelectionCard(payload, selectedRowIdxs, opts = {}) {
|
|
|
752
779
|
allRaw.push(rows[r]?.[c]);
|
|
753
780
|
if (n != null) allVals.push(n);
|
|
754
781
|
}
|
|
755
|
-
const total = reduce(allVals,
|
|
782
|
+
const total = reduce(allVals, colAgg, allRaw);
|
|
756
783
|
if (total != null && total > 0) sharePct = value / total * 100;
|
|
757
784
|
}
|
|
758
785
|
lines.push({
|
|
759
|
-
column: String(
|
|
760
|
-
label: `${aggLabel(
|
|
786
|
+
column: String(col?.name ?? ""),
|
|
787
|
+
label: `${aggLabel(colAgg)} of ${col?.name ?? ""}`,
|
|
761
788
|
value,
|
|
762
789
|
valueText: value == null ? "\u2014" : fmtNumber(value, opts.cultureCode),
|
|
763
790
|
sharePct,
|
|
764
|
-
shareText: sharePct == null ? "" : `${sharePct < 0.1 ? "<0.1" : sharePct.toFixed(1)}% of total
|
|
791
|
+
shareText: sharePct == null ? "" : `${sharePct < 0.1 ? "<0.1" : sharePct.toFixed(1)}% of total`,
|
|
792
|
+
aggregation: colAgg
|
|
793
|
+
});
|
|
794
|
+
}
|
|
795
|
+
const dimensionLines = [];
|
|
796
|
+
for (let c = 0; c < columns.length && dimensionLines.length < maxDimensions; c++) {
|
|
797
|
+
if (c === dimIdx) continue;
|
|
798
|
+
if (!isRealColumn(columns[c]) || isMeasureColumn(columns[c])) continue;
|
|
799
|
+
const name = String(columns[c]?.name ?? "");
|
|
800
|
+
const distinct = /* @__PURE__ */ new Set();
|
|
801
|
+
let firstText = "";
|
|
802
|
+
for (const p of positions) {
|
|
803
|
+
const raw = rows[p]?.[c];
|
|
804
|
+
const s = raw == null || raw === "" ? "(blank)" : String(raw);
|
|
805
|
+
if (!distinct.size) firstText = s;
|
|
806
|
+
distinct.add(s);
|
|
807
|
+
}
|
|
808
|
+
if (!distinct.size) continue;
|
|
809
|
+
const single = distinct.size === 1;
|
|
810
|
+
dimensionLines.push({
|
|
811
|
+
column: name,
|
|
812
|
+
label: single ? name : `Distinct ${name}`,
|
|
813
|
+
value: single ? null : distinct.size,
|
|
814
|
+
valueText: single ? firstText : fmtNumber(distinct.size, opts.cultureCode),
|
|
815
|
+
sharePct: null,
|
|
816
|
+
shareText: "",
|
|
817
|
+
aggregation: single ? "first" : "distinctcount"
|
|
765
818
|
});
|
|
766
819
|
}
|
|
767
820
|
return {
|
|
768
821
|
header,
|
|
769
822
|
lines,
|
|
823
|
+
dimensionLines,
|
|
824
|
+
suppressedColumns,
|
|
770
825
|
rowsText: `${positions.length} of ${rows.length} rows`,
|
|
771
826
|
selectedRows: positions.length,
|
|
772
827
|
totalRows: rows.length,
|
package/dist/react.mjs
CHANGED
|
@@ -1,7 +1,16 @@
|
|
|
1
1
|
import type { RenderPayload } from "./payload";
|
|
2
2
|
export interface SelectionCardOptions {
|
|
3
3
|
/** The chart's own aggregation, so the card AGREES with the picture it sits on. A card
|
|
4
|
-
* reading "Sum" beside a chart drawn from averages is two answers to one question.
|
|
4
|
+
* reading "Sum" beside a chart drawn from averages is two answers to one question.
|
|
5
|
+
*
|
|
6
|
+
* BLANK MEANS AUTO, and Auto is now per COLUMN. The Excel settings panel has offered
|
|
7
|
+
* "Auto — sum amounts, average rates" since the control shipped; `normaliseAggregation("")`
|
|
8
|
+
* answered `sum` for every column alike, so the label described a rule the code did not
|
|
9
|
+
* implement. A blank now resolves through `defaultAggregation` per column: amounts sum,
|
|
10
|
+
* rates average, dimensions report their value. A NAMED aggregation is still honoured
|
|
11
|
+
* wherever it is honest, and substituted per column where it is not — the label carries
|
|
12
|
+
* the substitution, so "Average of ChurnRate" beside "Sum of Revenue" reads as the answer
|
|
13
|
+
* it is rather than a silent override. */
|
|
5
14
|
aggregation?: string;
|
|
6
15
|
cultureCode?: string;
|
|
7
16
|
/** Cards are capped at roughly a third of the tile, so the measure list is capped too.
|
|
@@ -10,29 +19,55 @@ export interface SelectionCardOptions {
|
|
|
10
19
|
/** Past this many distinct dimension values the header becomes "N marks" — naming twelve
|
|
11
20
|
* cities in a header is not a header. */
|
|
12
21
|
maxHeaderValues?: number;
|
|
22
|
+
/** How many DIMENSION lines to add below the measures. Capped separately and small on
|
|
23
|
+
* purpose: dimensions must never crowd out the amounts, which is the failure the measure
|
|
24
|
+
* cap already had (on the sample table the two coordinate columns took two of the four
|
|
25
|
+
* measure slots and pushed the real measures under "+2 more"). Default 2. */
|
|
26
|
+
maxDimensions?: number;
|
|
13
27
|
}
|
|
14
28
|
export interface SelectionCardLine {
|
|
15
29
|
column: string;
|
|
16
|
-
/** "Sum of Revenue" — the aggregation is named because it is not always sum.
|
|
30
|
+
/** "Sum of Revenue" — the aggregation is named because it is not always sum. For a
|
|
31
|
+
* dimension resolving to ONE value it is just the column name, because "First of Segment:
|
|
32
|
+
* East" says nothing "Segment: East" does not. */
|
|
17
33
|
label: string;
|
|
34
|
+
/** Null for a dimension line, whose answer is text. `valueText` is what a host renders. */
|
|
18
35
|
value: number | null;
|
|
19
36
|
valueText: string;
|
|
20
|
-
/** Share of the same aggregate over ALL rows. Null whenever a share would be a lie —
|
|
21
|
-
*
|
|
37
|
+
/** Share of the same aggregate over ALL rows. Null whenever a share would be a lie — it
|
|
38
|
+
* needs BOTH an additive aggregation and an additive COLUMN. The average of a subset is
|
|
39
|
+
* not a percentage of the average of the whole; neither is a total of latitudes. */
|
|
22
40
|
sharePct: number | null;
|
|
23
41
|
shareText: string;
|
|
42
|
+
/** Which aggregation this line actually used, after any per-column substitution. */
|
|
43
|
+
aggregation: string;
|
|
24
44
|
}
|
|
25
45
|
export interface SelectionCardModel {
|
|
26
46
|
header: string;
|
|
47
|
+
/** MEASURE lines. Kept measures-only so `maxMeasures` and `hiddenMeasures` keep meaning
|
|
48
|
+
* exactly what they meant; dimensions have their own list and their own cap. */
|
|
27
49
|
lines: SelectionCardLine[];
|
|
50
|
+
/** DIMENSION lines — the "First, Count, Distinct" half. Before 2026-09-01 the FIRST dimension
|
|
51
|
+
* supplied the header and every other one was discarded, so on the sample table `Segment`
|
|
52
|
+
* appeared nowhere at all. The header column is still excluded here: it is already on
|
|
53
|
+
* screen. */
|
|
54
|
+
dimensionLines: SelectionCardLine[];
|
|
28
55
|
/** "6 of 24 rows" — the one line that is true regardless of what the columns contain. */
|
|
29
56
|
rowsText: string;
|
|
30
57
|
selectedRows: number;
|
|
31
58
|
totalRows: number;
|
|
32
59
|
/** Measures the cap left out, so a host can say "+2 more" instead of implying there were none. */
|
|
33
60
|
hiddenMeasures: number;
|
|
61
|
+
/** Columns the CLASSIFIER withheld rather than the cap — coordinates today. Not for display:
|
|
62
|
+
* a reader does not need telling that a latitude was not totalled. It is here so a host can
|
|
63
|
+
* log it, because a column vanishing from a card with no trace is the kind of thing that
|
|
64
|
+
* costs an afternoon later. */
|
|
65
|
+
suppressedColumns: string[];
|
|
34
66
|
aggregation: string;
|
|
35
67
|
}
|
|
68
|
+
/** The set this file reduces over. `first` is shape-core's eighth kind and is handled on the
|
|
69
|
+
* dimension path only, which is why it is absent here — a `reduce` over numbers has nothing to
|
|
70
|
+
* do with it. */
|
|
36
71
|
type Agg = "sum" | "average" | "min" | "max" | "count" | "median" | "distinctcount";
|
|
37
72
|
/** Normalise the many spellings the hosts use into the set this file reduces over. Unknown
|
|
38
73
|
* spellings fall back to sum rather than throwing: a card is a courtesy, and refusing to draw
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bicharts/chart-host",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.46",
|
|
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",
|