@bicharts/chart-host 0.6.112 → 0.6.115
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 +77 -6
- package/dist/adapters.mjs +3 -3
- package/dist/card.mjs +2 -2
- package/dist/{chunk-2KLFIGTQ.mjs → chunk-2GW3S5VD.mjs} +130 -16
- package/dist/{chunk-TE54AFRN.mjs → chunk-7K3F3RZ6.mjs} +473 -128
- package/dist/{chunk-7XT5OJ6M.mjs → chunk-AQO4ROMU.mjs} +1 -1
- package/dist/{chunk-IL5M7K6Z.mjs → chunk-CVTCR7HQ.mjs} +2 -2
- package/dist/{chunk-GTJG3SMD.mjs → chunk-DILJDN6C.mjs} +1 -1
- package/dist/{chunk-KY4FI2HA.mjs → chunk-GXR7T6G5.mjs} +1 -1
- package/dist/{chunk-KGVNZR23.mjs → chunk-PQKLWYKK.mjs} +1 -1
- package/dist/{chunk-PELRAFYZ.mjs → chunk-QLIRQJ6B.mjs} +1 -1
- package/dist/{chunk-FIG5DIW7.mjs → chunk-VPFP35XI.mjs} +72 -72
- package/dist/{chunk-AEO5SFEQ.mjs → chunk-YOCYWON4.mjs} +1 -1
- package/dist/{chunk-OLCUKXKL.mjs → chunk-YSRMSDRP.mjs} +1 -1
- package/dist/dax.mjs +1 -1
- package/dist/index.mjs +43 -9
- package/dist/legend-fit.mjs +3 -3
- package/dist/page.mjs +7 -5
- package/dist/provinces.mjs +1 -1
- package/dist/react.mjs +15 -12
- package/dist/testing.mjs +1 -1
- package/dist/types/contract.d.ts +14 -3
- package/dist/types/filterScope.d.ts +42 -3
- package/dist/types/host.d.ts +9 -5
- package/dist/types/index.d.ts +3 -1
- package/dist/types/keyboardMarks.d.ts +1 -1
- package/dist/types/markFollower.d.ts +21 -0
- package/dist/types/page.d.ts +1 -1
- package/dist/types/react.d.ts +11 -3
- package/dist/types/selectionMarker.d.ts +92 -0
- package/dist/zoom-memory.mjs +1 -1
- package/package.json +1 -1
|
@@ -4,11 +4,11 @@ import {
|
|
|
4
4
|
claimParkedLasso,
|
|
5
5
|
installLasso,
|
|
6
6
|
lassoEffect
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-CVTCR7HQ.mjs";
|
|
8
8
|
import {
|
|
9
9
|
censusHitBands,
|
|
10
10
|
ensureCrossfilterHitTargets
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-YOCYWON4.mjs";
|
|
12
12
|
import {
|
|
13
13
|
clearPress,
|
|
14
14
|
clearSelectionGlyphs,
|
|
@@ -24,26 +24,26 @@ import {
|
|
|
24
24
|
selectionRuleOf,
|
|
25
25
|
trackPress,
|
|
26
26
|
validRowSet
|
|
27
|
-
} from "./chunk-
|
|
27
|
+
} from "./chunk-PQKLWYKK.mjs";
|
|
28
28
|
import {
|
|
29
29
|
clipWindowOf,
|
|
30
30
|
fitRenderedChart,
|
|
31
31
|
rememberScroll,
|
|
32
32
|
takeScroll,
|
|
33
33
|
unpinScrolledAxis
|
|
34
|
-
} from "./chunk-
|
|
34
|
+
} from "./chunk-AQO4ROMU.mjs";
|
|
35
35
|
import {
|
|
36
36
|
geoFromCache
|
|
37
37
|
} from "./chunk-5YSZABCS.mjs";
|
|
38
38
|
import {
|
|
39
39
|
Fn,
|
|
40
|
+
Or,
|
|
40
41
|
Q,
|
|
41
42
|
Rt,
|
|
42
43
|
Yn,
|
|
43
|
-
_r,
|
|
44
44
|
tt,
|
|
45
45
|
xt
|
|
46
|
-
} from "./chunk-
|
|
46
|
+
} from "./chunk-VPFP35XI.mjs";
|
|
47
47
|
import {
|
|
48
48
|
ACTIVE_TICK_CLASS,
|
|
49
49
|
ANIM_LOOP_DELAY_DEFAULT,
|
|
@@ -88,7 +88,7 @@ import {
|
|
|
88
88
|
XFILTER_REFRESH_EVENT,
|
|
89
89
|
chartOwnsTimeline,
|
|
90
90
|
periodTickSuppressesFeedback
|
|
91
|
-
} from "./chunk-
|
|
91
|
+
} from "./chunk-GXR7T6G5.mjs";
|
|
92
92
|
|
|
93
93
|
// src/labelContrast.ts
|
|
94
94
|
function parseRGBA(c) {
|
|
@@ -554,6 +554,252 @@ function resolveAutoColorScale(p) {
|
|
|
554
554
|
return memoValue;
|
|
555
555
|
}
|
|
556
556
|
|
|
557
|
+
// src/selectionMarker.ts
|
|
558
|
+
var SELECTION_MARKER_DEFAULT = "auto";
|
|
559
|
+
var MAP_SELECTION_MARKER_DEFAULT = "outline";
|
|
560
|
+
function readSelectionMarker(raw) {
|
|
561
|
+
const v = typeof raw === "string" ? raw.trim().toLowerCase() : "";
|
|
562
|
+
return v === "none" || v === "dot" || v === "check" || v === "outline" || v === "auto" ? v : SELECTION_MARKER_DEFAULT;
|
|
563
|
+
}
|
|
564
|
+
function readMapSelectionMarker(raw) {
|
|
565
|
+
const v = typeof raw === "string" ? raw.trim().toLowerCase() : "";
|
|
566
|
+
return v === "none" || v === "dot" || v === "check" || v === "outline" ? v : MAP_SELECTION_MARKER_DEFAULT;
|
|
567
|
+
}
|
|
568
|
+
var REGION_JOIN_COLUMN = "__geoIso__";
|
|
569
|
+
function isRegionMapData(data) {
|
|
570
|
+
const cols = data?.columns;
|
|
571
|
+
if (!Array.isArray(cols)) return false;
|
|
572
|
+
return cols.some((c) => !!c && c.name === REGION_JOIN_COLUMN);
|
|
573
|
+
}
|
|
574
|
+
var NEUTRAL_CENTRE_RAMP_SELECTOR = '.llm-value-ramp[data-kind="diverging"]';
|
|
575
|
+
function hasNeutralCentreRamp(container) {
|
|
576
|
+
try {
|
|
577
|
+
return !!container?.querySelector?.(NEUTRAL_CENTRE_RAMP_SELECTOR);
|
|
578
|
+
} catch {
|
|
579
|
+
return false;
|
|
580
|
+
}
|
|
581
|
+
}
|
|
582
|
+
function selectionMarkerFor(facts) {
|
|
583
|
+
if (facts.regionMap) return readMapSelectionMarker(facts.mapChoice);
|
|
584
|
+
const c = readSelectionMarker(facts.choice);
|
|
585
|
+
if (c !== "auto") return c;
|
|
586
|
+
return facts.neutralCentreRamp ? "outline" : "none";
|
|
587
|
+
}
|
|
588
|
+
var SELECTION_OUTLINE_CLASS = "lch-sel-outline";
|
|
589
|
+
var SVG_NS = "http://www.w3.org/2000/svg";
|
|
590
|
+
var AREA_TAGS = /* @__PURE__ */ new Set(["path", "rect", "polygon"]);
|
|
591
|
+
var UNFILLED = /^(none|transparent|rgba\([^)]*,\s*0(\.0+)?\s*\))$/i;
|
|
592
|
+
function isAreaMark(el) {
|
|
593
|
+
const tag = (el.localName || el.tagName || "").toLowerCase();
|
|
594
|
+
if (!AREA_TAGS.has(tag)) return false;
|
|
595
|
+
let fill = "", fillOpacity = "";
|
|
596
|
+
try {
|
|
597
|
+
const cs = el.ownerDocument?.defaultView?.getComputedStyle?.(el);
|
|
598
|
+
fill = (cs?.fill || "").trim();
|
|
599
|
+
fillOpacity = (cs?.fillOpacity || "").trim();
|
|
600
|
+
} catch {
|
|
601
|
+
}
|
|
602
|
+
const style = el.style;
|
|
603
|
+
if (!fill) fill = (style?.fill || el.getAttribute("fill") || "").trim();
|
|
604
|
+
if (!fillOpacity) fillOpacity = (style?.fillOpacity || el.getAttribute("fill-opacity") || "").trim();
|
|
605
|
+
if (fill && UNFILLED.test(fill)) return false;
|
|
606
|
+
if (fillOpacity !== "" && parseFloat(fillOpacity) === 0) return false;
|
|
607
|
+
return true;
|
|
608
|
+
}
|
|
609
|
+
function collectOutlineMarks(container, filter) {
|
|
610
|
+
const picked = [];
|
|
611
|
+
const seen = /* @__PURE__ */ new Set();
|
|
612
|
+
const add = (el) => {
|
|
613
|
+
if (seen.has(el)) return;
|
|
614
|
+
seen.add(el);
|
|
615
|
+
if (isAreaMark(el)) picked.push(el);
|
|
616
|
+
};
|
|
617
|
+
for (const m of Array.from(container.querySelectorAll(`.${MARK_CLASS}.${MARK_SELECTED_CLASS}`))) {
|
|
618
|
+
if (filter?.shown && !filter.shown(m)) continue;
|
|
619
|
+
if ((m.localName || "").toLowerCase() === "g") {
|
|
620
|
+
for (const s of Array.from(m.querySelectorAll("path, rect, polygon"))) add(s);
|
|
621
|
+
} else add(m);
|
|
622
|
+
}
|
|
623
|
+
if (picked.length < 2 || picked.length > 300) return picked;
|
|
624
|
+
const EPS2 = 1;
|
|
625
|
+
const rects = picked.map((m) => {
|
|
626
|
+
try {
|
|
627
|
+
return m.getBoundingClientRect();
|
|
628
|
+
} catch {
|
|
629
|
+
return null;
|
|
630
|
+
}
|
|
631
|
+
});
|
|
632
|
+
return picked.filter((_, i) => {
|
|
633
|
+
const c = rects[i];
|
|
634
|
+
if (!c) return true;
|
|
635
|
+
const cArea = c.width * c.height;
|
|
636
|
+
if (!(cArea > 0)) return true;
|
|
637
|
+
for (let j = 0; j < rects.length; j++) {
|
|
638
|
+
const r = rects[j];
|
|
639
|
+
if (j === i || !r) continue;
|
|
640
|
+
const a = r.width * r.height;
|
|
641
|
+
if (!(a > 0) || a >= cArea) continue;
|
|
642
|
+
if (r.left >= c.left - EPS2 && r.right <= c.right + EPS2 && r.top >= c.top - EPS2 && r.bottom <= c.bottom + EPS2) return false;
|
|
643
|
+
}
|
|
644
|
+
return true;
|
|
645
|
+
});
|
|
646
|
+
}
|
|
647
|
+
function outlineWindowOf(mark, stop) {
|
|
648
|
+
let acc = null;
|
|
649
|
+
const narrow = (w) => {
|
|
650
|
+
if (!w) return;
|
|
651
|
+
acc = acc ? {
|
|
652
|
+
left: Math.max(acc.left, w.left),
|
|
653
|
+
top: Math.max(acc.top, w.top),
|
|
654
|
+
right: Math.min(acc.right, w.right),
|
|
655
|
+
bottom: Math.min(acc.bottom, w.bottom)
|
|
656
|
+
} : { ...w };
|
|
657
|
+
};
|
|
658
|
+
for (let el = mark; el && el !== stop; el = el.parentElement) {
|
|
659
|
+
try {
|
|
660
|
+
if ((el.localName || "").toLowerCase() === "svg") {
|
|
661
|
+
const r = el.getBoundingClientRect();
|
|
662
|
+
if (r.width > 0 && r.height > 0) narrow({ left: r.left, top: r.top, right: r.right, bottom: r.bottom });
|
|
663
|
+
} else if (el.hasAttribute?.("clip-path")) narrow(clipWindowOf(el));
|
|
664
|
+
} catch {
|
|
665
|
+
}
|
|
666
|
+
}
|
|
667
|
+
return acc;
|
|
668
|
+
}
|
|
669
|
+
function controlBoxesIn(root, opts = {}) {
|
|
670
|
+
const pad = opts.pad ?? 2, join = opts.join ?? 4;
|
|
671
|
+
let boxes = [];
|
|
672
|
+
try {
|
|
673
|
+
for (const el of Array.from(root?.querySelectorAll?.(`.${CONTROL_CLASS}`) ?? [])) {
|
|
674
|
+
const r = el.getBoundingClientRect();
|
|
675
|
+
if (!(r.width > 0) || !(r.height > 0)) continue;
|
|
676
|
+
boxes.push({ left: r.left - pad, top: r.top - pad, right: r.right + pad, bottom: r.bottom + pad });
|
|
677
|
+
}
|
|
678
|
+
} catch {
|
|
679
|
+
return [];
|
|
680
|
+
}
|
|
681
|
+
const near = (a, b) => a.left - join <= b.right && b.left - join <= a.right && a.top - join <= b.bottom && b.top - join <= a.bottom;
|
|
682
|
+
let merged = true;
|
|
683
|
+
while (merged) {
|
|
684
|
+
merged = false;
|
|
685
|
+
const out = [];
|
|
686
|
+
for (const b of boxes) {
|
|
687
|
+
const hit = out.find((o) => near(o, b));
|
|
688
|
+
if (hit) {
|
|
689
|
+
hit.left = Math.min(hit.left, b.left);
|
|
690
|
+
hit.top = Math.min(hit.top, b.top);
|
|
691
|
+
hit.right = Math.max(hit.right, b.right);
|
|
692
|
+
hit.bottom = Math.max(hit.bottom, b.bottom);
|
|
693
|
+
merged = true;
|
|
694
|
+
} else out.push({ ...b });
|
|
695
|
+
}
|
|
696
|
+
boxes = out;
|
|
697
|
+
}
|
|
698
|
+
return boxes;
|
|
699
|
+
}
|
|
700
|
+
function copyGeometry(doc, el) {
|
|
701
|
+
const tag = (el.localName || "").toLowerCase();
|
|
702
|
+
const keep = tag === "path" ? ["d"] : tag === "rect" ? ["x", "y", "width", "height", "rx", "ry"] : tag === "polygon" ? ["points"] : null;
|
|
703
|
+
if (!keep) return null;
|
|
704
|
+
const out = doc.createElementNS(SVG_NS, tag);
|
|
705
|
+
let any = false;
|
|
706
|
+
for (const a of keep) {
|
|
707
|
+
const v = el.getAttribute(a);
|
|
708
|
+
if (v != null && v !== "") {
|
|
709
|
+
out.setAttribute(a, v);
|
|
710
|
+
any = true;
|
|
711
|
+
}
|
|
712
|
+
}
|
|
713
|
+
return any ? out : null;
|
|
714
|
+
}
|
|
715
|
+
var num = (n) => String(Math.round(n * 1e3) / 1e3);
|
|
716
|
+
var maskSeq = 0;
|
|
717
|
+
function paintSelectionOutlines(overlay, marks, style) {
|
|
718
|
+
const doc = overlay.ownerDocument;
|
|
719
|
+
const base = overlay.getBoundingClientRect();
|
|
720
|
+
const width = style.width ?? 2;
|
|
721
|
+
const windowOf = style.windowOf ?? ((m) => outlineWindowOf(m));
|
|
722
|
+
const root = doc.createElementNS(SVG_NS, "svg");
|
|
723
|
+
root.setAttribute("class", SELECTION_OUTLINE_CLASS);
|
|
724
|
+
root.setAttribute("aria-hidden", "true");
|
|
725
|
+
root.setAttribute("focusable", "false");
|
|
726
|
+
root.setAttribute("style", "position:absolute;left:0;top:0;width:1px;height:1px;overflow:visible;pointer-events:none");
|
|
727
|
+
let host = root;
|
|
728
|
+
const holes = (style.avoid ?? []).filter((b) => b.right > b.left && b.bottom > b.top);
|
|
729
|
+
if (holes.length) {
|
|
730
|
+
const id = `${SELECTION_OUTLINE_CLASS}-mask-${++maskSeq}`;
|
|
731
|
+
const defs = doc.createElementNS(SVG_NS, "defs");
|
|
732
|
+
const mask = doc.createElementNS(SVG_NS, "mask");
|
|
733
|
+
mask.setAttribute("id", id);
|
|
734
|
+
mask.setAttribute("maskUnits", "userSpaceOnUse");
|
|
735
|
+
const BIG = 1e5;
|
|
736
|
+
for (const [k, v] of [["x", -BIG], ["y", -BIG], ["width", 2 * BIG], ["height", 2 * BIG]]) mask.setAttribute(k, String(v));
|
|
737
|
+
const open = doc.createElementNS(SVG_NS, "rect");
|
|
738
|
+
for (const [k, v] of [["x", -BIG], ["y", -BIG], ["width", 2 * BIG], ["height", 2 * BIG]]) open.setAttribute(k, String(v));
|
|
739
|
+
open.setAttribute("fill", "#fff");
|
|
740
|
+
mask.appendChild(open);
|
|
741
|
+
for (const b of holes) {
|
|
742
|
+
const r = doc.createElementNS(SVG_NS, "rect");
|
|
743
|
+
r.setAttribute("class", `${SELECTION_OUTLINE_CLASS}-hole`);
|
|
744
|
+
r.setAttribute("x", num(b.left - base.left));
|
|
745
|
+
r.setAttribute("y", num(b.top - base.top));
|
|
746
|
+
r.setAttribute("width", num(b.right - b.left));
|
|
747
|
+
r.setAttribute("height", num(b.bottom - b.top));
|
|
748
|
+
r.setAttribute("fill", "#000");
|
|
749
|
+
mask.appendChild(r);
|
|
750
|
+
}
|
|
751
|
+
defs.appendChild(mask);
|
|
752
|
+
root.appendChild(defs);
|
|
753
|
+
host = doc.createElementNS(SVG_NS, "g");
|
|
754
|
+
host.setAttribute("mask", `url(#${id})`);
|
|
755
|
+
root.appendChild(host);
|
|
756
|
+
}
|
|
757
|
+
let drawn = 0;
|
|
758
|
+
const max = style.max ?? 600;
|
|
759
|
+
for (const m of marks) {
|
|
760
|
+
if (drawn >= max) break;
|
|
761
|
+
let ctm = null;
|
|
762
|
+
try {
|
|
763
|
+
ctm = m.getScreenCTM?.() ?? null;
|
|
764
|
+
} catch {
|
|
765
|
+
ctm = null;
|
|
766
|
+
}
|
|
767
|
+
if (!ctm) continue;
|
|
768
|
+
const shape = copyGeometry(doc, m);
|
|
769
|
+
if (!shape) continue;
|
|
770
|
+
let parent = host;
|
|
771
|
+
let ox = base.left, oy = base.top;
|
|
772
|
+
const w = windowOf(m);
|
|
773
|
+
if (w) {
|
|
774
|
+
if (!(w.right > w.left) || !(w.bottom > w.top)) continue;
|
|
775
|
+
const v = doc.createElementNS(SVG_NS, "svg");
|
|
776
|
+
v.setAttribute("x", num(w.left - base.left));
|
|
777
|
+
v.setAttribute("y", num(w.top - base.top));
|
|
778
|
+
v.setAttribute("width", num(w.right - w.left));
|
|
779
|
+
v.setAttribute("height", num(w.bottom - w.top));
|
|
780
|
+
v.setAttribute("overflow", "hidden");
|
|
781
|
+
host.appendChild(v);
|
|
782
|
+
parent = v;
|
|
783
|
+
ox = w.left;
|
|
784
|
+
oy = w.top;
|
|
785
|
+
}
|
|
786
|
+
const transform = `matrix(${num(ctm.a)} ${num(ctm.b)} ${num(ctm.c)} ${num(ctm.d)} ${num(ctm.e - ox)} ${num(ctm.f - oy)})`;
|
|
787
|
+
for (const [stroke, sw] of [[style.halo, width + 2], [style.color, width]]) {
|
|
788
|
+
const p = shape.cloneNode(false);
|
|
789
|
+
p.setAttribute("transform", transform);
|
|
790
|
+
p.setAttribute("fill", "none");
|
|
791
|
+
p.setAttribute("stroke", stroke);
|
|
792
|
+
p.setAttribute("stroke-width", String(sw));
|
|
793
|
+
p.setAttribute("stroke-linejoin", "round");
|
|
794
|
+
p.setAttribute("vector-effect", "non-scaling-stroke");
|
|
795
|
+
parent.appendChild(p);
|
|
796
|
+
}
|
|
797
|
+
drawn++;
|
|
798
|
+
}
|
|
799
|
+
if (drawn > 0) overlay.appendChild(root);
|
|
800
|
+
return drawn;
|
|
801
|
+
}
|
|
802
|
+
|
|
557
803
|
// src/exportTable.ts
|
|
558
804
|
var EXPORT_FORMATS = Object.freeze(["xlsx", "csv"]);
|
|
559
805
|
var XLSX_MIME = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
|
|
@@ -1169,12 +1415,20 @@ function resolveOptions(p) {
|
|
|
1169
1415
|
const n = typeof v === "number" ? v : typeof v === "string" && v.trim() !== "" ? Number(v) : NaN;
|
|
1170
1416
|
return Number.isFinite(n) ? clamp(n, DIM_OPACITY_MIN, 1) : void 0;
|
|
1171
1417
|
})(),
|
|
1172
|
-
// A recognised
|
|
1173
|
-
//
|
|
1418
|
+
// A recognised marker or nothing: an unknown string must never reach the painter as a live mode. "none" and
|
|
1419
|
+
// "auto" read undefined here, as a host that passes nothing does; what tells them apart is selectionMarker.
|
|
1174
1420
|
selectionGlyph: (() => {
|
|
1175
1421
|
const v = (p.selectionGlyph == null ? "" : String(p.selectionGlyph)).toLowerCase();
|
|
1176
|
-
return v === "dot" || v === "check" ? v : void 0;
|
|
1422
|
+
return v === "dot" || v === "check" || v === "outline" ? v : void 0;
|
|
1423
|
+
})(),
|
|
1424
|
+
// THE WHOLE CHOICE: absent, unknown and "auto" are the default ("auto"), and "none" is a reader's None. The map's
|
|
1425
|
+
// choice beside it, its default "outline" when it made none.
|
|
1426
|
+
selectionMarker: readSelectionMarker(p.selectionGlyph),
|
|
1427
|
+
mapSelectionGlyph: (() => {
|
|
1428
|
+
const v = (p.mapSelectionGlyph == null ? "" : String(p.mapSelectionGlyph)).toLowerCase();
|
|
1429
|
+
return v === "none" || v === "dot" || v === "check" || v === "outline" ? v : void 0;
|
|
1177
1430
|
})(),
|
|
1431
|
+
mapSelectionMarker: readMapSelectionMarker(p.mapSelectionGlyph),
|
|
1178
1432
|
// A host FACT from the generate answer, true only for a literal true: silence never suppresses anything.
|
|
1179
1433
|
suppressSelectionGlyph: p.suppressSelectionGlyph === true ? true : void 0,
|
|
1180
1434
|
// A host FACT (1.22.0): the chart works from the keyboard. True only for a literal true, like the one above.
|
|
@@ -1319,7 +1573,7 @@ function resolvePointChannel(cols, rowObjs, point) {
|
|
|
1319
1573
|
let labelCol;
|
|
1320
1574
|
if (bind) {
|
|
1321
1575
|
const dims = cols.filter((c) => !c.isMeasure).map((c) => c.name);
|
|
1322
|
-
const res =
|
|
1576
|
+
const res = Or(dims, rowObjs, bind, point?.mapKind, cols.map((c) => c.name));
|
|
1323
1577
|
bind = res.bind;
|
|
1324
1578
|
rolesBackfilled = res.backfilled;
|
|
1325
1579
|
rolesRefused = res.refused;
|
|
@@ -1634,6 +1888,93 @@ function stripJsComments(code) {
|
|
|
1634
1888
|
return out;
|
|
1635
1889
|
}
|
|
1636
1890
|
|
|
1891
|
+
// src/markFollower.ts
|
|
1892
|
+
var MARK_MOVE_ATTRIBUTES = Object.freeze([
|
|
1893
|
+
"transform",
|
|
1894
|
+
"d",
|
|
1895
|
+
"x",
|
|
1896
|
+
"y",
|
|
1897
|
+
"cx",
|
|
1898
|
+
"cy",
|
|
1899
|
+
"points",
|
|
1900
|
+
"width",
|
|
1901
|
+
"height",
|
|
1902
|
+
"visibility",
|
|
1903
|
+
"opacity",
|
|
1904
|
+
"style",
|
|
1905
|
+
"class"
|
|
1906
|
+
]);
|
|
1907
|
+
function followMarks(container, opts) {
|
|
1908
|
+
const win = opts.win ?? container.ownerDocument?.defaultView ?? null;
|
|
1909
|
+
let observer = null;
|
|
1910
|
+
let resize = null;
|
|
1911
|
+
let size = "";
|
|
1912
|
+
let queued = false;
|
|
1913
|
+
let queuedResize = false;
|
|
1914
|
+
const sizeOf = () => `${container.offsetWidth ?? 0}x${container.offsetHeight ?? 0}`;
|
|
1915
|
+
const movesAMark = (r) => {
|
|
1916
|
+
const t = r.target;
|
|
1917
|
+
if (!t || opts.blind && t.closest?.(opts.blind)) return false;
|
|
1918
|
+
return !!(t.classList?.contains(MARK_CLASS) || t.querySelector?.(`.${MARK_CLASS}`));
|
|
1919
|
+
};
|
|
1920
|
+
const queue = (resized) => {
|
|
1921
|
+
if (resized) queuedResize = true;
|
|
1922
|
+
if (queued) return;
|
|
1923
|
+
queued = true;
|
|
1924
|
+
const run = () => {
|
|
1925
|
+
const r = queuedResize;
|
|
1926
|
+
queued = false;
|
|
1927
|
+
queuedResize = false;
|
|
1928
|
+
if (observer || resize) {
|
|
1929
|
+
try {
|
|
1930
|
+
opts.repaint(r);
|
|
1931
|
+
} catch {
|
|
1932
|
+
}
|
|
1933
|
+
}
|
|
1934
|
+
};
|
|
1935
|
+
if (win?.requestAnimationFrame) win.requestAnimationFrame(run);
|
|
1936
|
+
else setTimeout(run, 16);
|
|
1937
|
+
};
|
|
1938
|
+
return {
|
|
1939
|
+
follow(on) {
|
|
1940
|
+
if (!on) {
|
|
1941
|
+
if (observer) {
|
|
1942
|
+
observer.disconnect();
|
|
1943
|
+
observer = null;
|
|
1944
|
+
}
|
|
1945
|
+
if (resize) {
|
|
1946
|
+
resize.disconnect();
|
|
1947
|
+
resize = null;
|
|
1948
|
+
}
|
|
1949
|
+
return;
|
|
1950
|
+
}
|
|
1951
|
+
const MO = win?.MutationObserver;
|
|
1952
|
+
if (!observer && MO) {
|
|
1953
|
+
observer = new MO((records) => {
|
|
1954
|
+
if (!queued && records.some(movesAMark)) queue(false);
|
|
1955
|
+
});
|
|
1956
|
+
observer.observe(container, { subtree: true, attributes: true, attributeFilter: [...MARK_MOVE_ATTRIBUTES] });
|
|
1957
|
+
}
|
|
1958
|
+
const RO = win?.ResizeObserver;
|
|
1959
|
+
if (!resize && RO) {
|
|
1960
|
+
resize = new RO(() => {
|
|
1961
|
+
if (sizeOf() !== size) queue(true);
|
|
1962
|
+
});
|
|
1963
|
+
resize.observe(container);
|
|
1964
|
+
}
|
|
1965
|
+
},
|
|
1966
|
+
painted() {
|
|
1967
|
+
size = sizeOf();
|
|
1968
|
+
},
|
|
1969
|
+
takeRecords() {
|
|
1970
|
+
observer?.takeRecords();
|
|
1971
|
+
},
|
|
1972
|
+
get following() {
|
|
1973
|
+
return !!(observer || resize);
|
|
1974
|
+
}
|
|
1975
|
+
};
|
|
1976
|
+
}
|
|
1977
|
+
|
|
1637
1978
|
// src/blankRender.ts
|
|
1638
1979
|
var EMPTY2 = { markCount: 0, legendMarkCount: 0, containerKind: "empty", declaresNoRowMarks: false };
|
|
1639
1980
|
function censusMarks(container) {
|
|
@@ -1722,7 +2063,7 @@ var FIT_SAMPLE = 90;
|
|
|
1722
2063
|
var VALUE_AXIS_MIN_FIT = 0.8;
|
|
1723
2064
|
var MIN_AXIS_SPAN_PX = 40;
|
|
1724
2065
|
var EMPTY3 = { marks: 0, axis: "", column: "", fit: 0, offShare: 0, medianOffRadii: 0 };
|
|
1725
|
-
function
|
|
2066
|
+
function num2(el, name) {
|
|
1726
2067
|
const v = el.getAttribute?.(name);
|
|
1727
2068
|
if (v === null || v === void 0 || String(v).trim() === "") return NaN;
|
|
1728
2069
|
return parseFloat(String(v));
|
|
@@ -1767,7 +2108,7 @@ function censusValuePlacement(container, data) {
|
|
|
1767
2108
|
if (!/^\d+$/.test(raw)) continue;
|
|
1768
2109
|
const i = +raw;
|
|
1769
2110
|
const row = rows[i];
|
|
1770
|
-
const x =
|
|
2111
|
+
const x = num2(el, "cx"), y = num2(el, "cy"), r = num2(el, "r");
|
|
1771
2112
|
if (!row || !Number.isFinite(x) || !Number.isFinite(y) || !(r > 0)) continue;
|
|
1772
2113
|
seen.add(i);
|
|
1773
2114
|
dots.push({ row, x, y, r });
|
|
@@ -1929,11 +2270,11 @@ function extendPillOver(pill, tr) {
|
|
|
1929
2270
|
const inv = m.inverse();
|
|
1930
2271
|
const toUser = (x2, y2) => ({ x: inv.a * x2 + inv.c * y2 + inv.e, y: inv.b * x2 + inv.d * y2 + inv.f });
|
|
1931
2272
|
const a = toUser(tr.left, tr.top), b = toUser(tr.right, tr.bottom);
|
|
1932
|
-
const
|
|
2273
|
+
const num3 = (k) => {
|
|
1933
2274
|
const v = parseFloat(pill.getAttribute(k) || "");
|
|
1934
2275
|
return isFinite(v) ? v : NaN;
|
|
1935
2276
|
};
|
|
1936
|
-
const x =
|
|
2277
|
+
const x = num3("x"), y = num3("y"), w = num3("width"), h = num3("height");
|
|
1937
2278
|
if (![x, y, w, h].every((v) => isFinite(v)) || !(w > 0) || !(h > 0)) return false;
|
|
1938
2279
|
const pad = 1 / m.a;
|
|
1939
2280
|
const x0 = Math.min(x, Math.min(a.x, b.x) - pad), x1 = Math.max(x + w, Math.max(a.x, b.x) + pad);
|
|
@@ -2340,10 +2681,10 @@ function seenRight(el, right, stop) {
|
|
|
2340
2681
|
}
|
|
2341
2682
|
return right;
|
|
2342
2683
|
}
|
|
2343
|
-
var
|
|
2684
|
+
var SVG_NS2 = "http://www.w3.org/2000/svg";
|
|
2344
2685
|
function overflowWindowOf(el) {
|
|
2345
2686
|
const win = el.ownerDocument.defaultView;
|
|
2346
|
-
if (!win || el.namespaceURI ===
|
|
2687
|
+
if (!win || el.namespaceURI === SVG_NS2) return null;
|
|
2347
2688
|
try {
|
|
2348
2689
|
const o = win.getComputedStyle(el);
|
|
2349
2690
|
const clips = (v) => !!v && v !== "visible";
|
|
@@ -2426,17 +2767,22 @@ function createAnnotationLayer(container, onClick, opts) {
|
|
|
2426
2767
|
const names = (data.columns || []).map((c) => typeof c === "string" ? c : c?.name);
|
|
2427
2768
|
const marks = Array.from(container.querySelectorAll(`.${MARK_CLASS}[${ROW_IDX_ATTR}]`)).filter((m) => !m.closest(`.${ANNOTATION_LAYER_CLASS}`));
|
|
2428
2769
|
const marksByRow = /* @__PURE__ */ new Map();
|
|
2429
|
-
|
|
2430
|
-
|
|
2431
|
-
|
|
2432
|
-
|
|
2770
|
+
const rowsOf = /* @__PURE__ */ new Map();
|
|
2771
|
+
for (const m of marks) {
|
|
2772
|
+
const own = new Set(parseIdxs(m.getAttribute(ROW_IDX_ATTR)));
|
|
2773
|
+
rowsOf.set(m, own);
|
|
2774
|
+
for (const r of own) {
|
|
2775
|
+
const at = marksByRow.get(r);
|
|
2776
|
+
if (at) at.push(m);
|
|
2777
|
+
else marksByRow.set(r, [m]);
|
|
2778
|
+
}
|
|
2433
2779
|
}
|
|
2434
2780
|
const origin = container.getBoundingClientRect();
|
|
2435
2781
|
const open = origin.width > 0 && origin.height > 0 ? box(origin) : FREE;
|
|
2436
2782
|
const clipOf = /* @__PURE__ */ new Map();
|
|
2437
2783
|
const windowOf = (el) => {
|
|
2438
2784
|
if (!clipOf.has(el)) {
|
|
2439
|
-
if (el.namespaceURI ===
|
|
2785
|
+
if (el.namespaceURI === SVG_NS2) {
|
|
2440
2786
|
const w = clipWindowOf(el);
|
|
2441
2787
|
clipOf.set(el, w && box(w));
|
|
2442
2788
|
} else clipOf.set(el, overflowWindowOf(el));
|
|
@@ -2451,7 +2797,7 @@ function createAnnotationLayer(container, onClick, opts) {
|
|
|
2451
2797
|
const viewOf = (m) => {
|
|
2452
2798
|
let v = inView;
|
|
2453
2799
|
for (let el = m.parentElement; v && el && el !== container; el = el.parentElement) {
|
|
2454
|
-
if (el.namespaceURI ===
|
|
2800
|
+
if (el.namespaceURI === SVG_NS2 && el.localName === "svg") {
|
|
2455
2801
|
const s = el.getBoundingClientRect();
|
|
2456
2802
|
if (s.width > 0 && s.height > 0) v = cut(v, box(s));
|
|
2457
2803
|
}
|
|
@@ -2546,16 +2892,31 @@ function createAnnotationLayer(container, onClick, opts) {
|
|
|
2546
2892
|
for (const a of list) {
|
|
2547
2893
|
const pairs = (a.where ? Object.entries(a.where) : a.column != null ? [[a.column, a.value]] : []).map(([c, v]) => [names.indexOf(c), text(v)]);
|
|
2548
2894
|
const want = pairs.map((p) => p[1]).join(" / ");
|
|
2549
|
-
const hits2 = /* @__PURE__ */ new Set();
|
|
2895
|
+
const hits2 = /* @__PURE__ */ new Set(), keyRows = /* @__PURE__ */ new Set();
|
|
2550
2896
|
if (pairs.length && pairs.every((p) => p[0] >= 0)) (data.rows || []).forEach((row, r) => {
|
|
2551
|
-
if (pairs.every(([ci, v]) => text(row?.[ci]) === v))
|
|
2897
|
+
if (!pairs.every(([ci, v]) => text(row?.[ci]) === v)) return;
|
|
2898
|
+
keyRows.add(r);
|
|
2899
|
+
for (const m of marksByRow.get(r) ?? []) hits2.add(m);
|
|
2552
2900
|
});
|
|
2553
2901
|
if (!hits2.size) continue;
|
|
2554
|
-
|
|
2902
|
+
const rank = (m) => {
|
|
2903
|
+
const own = rowsOf.get(m);
|
|
2904
|
+
let out = 0;
|
|
2905
|
+
for (const r of own) if (!keyRows.has(r)) out++;
|
|
2906
|
+
const level = parseInt(m.getAttribute("aria-level") || "", 10);
|
|
2907
|
+
return [out, out === 0 && own.size === keyRows.size ? 0 : 1, own.size, Number.isFinite(level) ? -level : 0];
|
|
2908
|
+
};
|
|
2909
|
+
const before = (p, q) => p[0] - q[0] || p[1] - q[1] || p[2] - q[2] || p[3] - q[3];
|
|
2910
|
+
const drawn = [];
|
|
2555
2911
|
for (const m of hits2) {
|
|
2556
2912
|
const b = m.getBoundingClientRect();
|
|
2557
|
-
if (
|
|
2558
|
-
|
|
2913
|
+
if (b.width > 0 && b.height > 0) drawn.push({ m, b, k: rank(m) });
|
|
2914
|
+
}
|
|
2915
|
+
const laidOut = drawn.length > 0;
|
|
2916
|
+
const most = drawn.reduce((k, d) => !k || before(d.k, k) < 0 ? d.k : k, null);
|
|
2917
|
+
let best = null, bestWhole = null, bestMark = null;
|
|
2918
|
+
for (const { m, b, k } of drawn) {
|
|
2919
|
+
if (before(k, most) !== 0) continue;
|
|
2559
2920
|
const v = cut(box(b), viewOf(m));
|
|
2560
2921
|
if (v && (!best || area(v) > area(best))) {
|
|
2561
2922
|
best = v;
|
|
@@ -2815,16 +3176,17 @@ function installKeyboard(env) {
|
|
|
2815
3176
|
const { container } = env;
|
|
2816
3177
|
let rovingKey = null;
|
|
2817
3178
|
let destroyed = false;
|
|
2818
|
-
const
|
|
2819
|
-
|
|
2820
|
-
return Array.from(container.querySelectorAll(env.markSelector)).filter((m) => !m.closest(env.skipSelector) && (m.getAttribute("data-row-idx") ?? "") !== "");
|
|
2821
|
-
};
|
|
3179
|
+
const ownRole = /* @__PURE__ */ new WeakSet();
|
|
3180
|
+
const marksNow = () => Array.from(container.querySelectorAll(env.markSelector)).filter((m) => !m.closest(env.skipSelector) && (m.getAttribute("data-row-idx") ?? "") !== "");
|
|
2822
3181
|
const wired = (el) => el.hasAttribute(WIRED_ATTR);
|
|
2823
3182
|
const wire = (el, tabindex, role) => {
|
|
2824
3183
|
if (el.hasAttribute("tabindex") && !wired(el)) return false;
|
|
2825
3184
|
el.setAttribute(WIRED_ATTR, "");
|
|
2826
3185
|
el.setAttribute("tabindex", tabindex);
|
|
2827
|
-
if (!el.hasAttribute("role")
|
|
3186
|
+
if (!el.hasAttribute("role") || ownRole.has(el)) {
|
|
3187
|
+
el.setAttribute("role", role);
|
|
3188
|
+
ownRole.add(el);
|
|
3189
|
+
}
|
|
2828
3190
|
return true;
|
|
2829
3191
|
};
|
|
2830
3192
|
const setRoving = (list, to) => {
|
|
@@ -2835,22 +3197,17 @@ function installKeyboard(env) {
|
|
|
2835
3197
|
if (destroyed) return;
|
|
2836
3198
|
try {
|
|
2837
3199
|
container.classList?.add(KEYBOARD_CLASS);
|
|
3200
|
+
const inert = env.inert();
|
|
2838
3201
|
const list = marksNow();
|
|
2839
3202
|
for (const m of list) {
|
|
2840
|
-
if (!wire(m, "-1", "button")) continue;
|
|
2841
|
-
m.
|
|
3203
|
+
if (!wire(m, "-1", inert ? "img" : "button")) continue;
|
|
3204
|
+
if (inert) m.removeAttribute("aria-pressed");
|
|
3205
|
+
else m.setAttribute("aria-pressed", env.isSelected(m) ? "true" : "false");
|
|
2842
3206
|
if (!m.hasAttribute("aria-label") && !m.querySelector(":scope > title")) {
|
|
2843
3207
|
const name = env.labelOf(m);
|
|
2844
3208
|
if (name) m.setAttribute("aria-label", name);
|
|
2845
3209
|
}
|
|
2846
3210
|
}
|
|
2847
|
-
if (!list.length) {
|
|
2848
|
-
for (const m of Array.from(container.querySelectorAll(`[${WIRED_ATTR}]`)))
|
|
2849
|
-
if (m.matches(env.markSelector)) {
|
|
2850
|
-
m.removeAttribute("tabindex");
|
|
2851
|
-
m.removeAttribute(WIRED_ATTR);
|
|
2852
|
-
}
|
|
2853
|
-
}
|
|
2854
3211
|
const own = list.filter(wired);
|
|
2855
3212
|
if (own.length) {
|
|
2856
3213
|
const keep = own.find((m) => env.keyOf(m) === rovingKey) ?? own.find((m) => env.isSelected(m)) ?? own[0];
|
|
@@ -2879,7 +3236,7 @@ function installKeyboard(env) {
|
|
|
2879
3236
|
e.preventDefault();
|
|
2880
3237
|
const ME = container.ownerDocument.defaultView?.MouseEvent ?? MouseEvent;
|
|
2881
3238
|
press.dispatchEvent(new ME("click", { bubbles: true, cancelable: true }));
|
|
2882
|
-
} else if (k === "Escape" && env.escapeClears !== false) env.clear();
|
|
3239
|
+
} else if (k === "Escape" && env.escapeClears !== false && !env.inert()) env.clear();
|
|
2883
3240
|
return;
|
|
2884
3241
|
}
|
|
2885
3242
|
const mark = t.closest?.(env.markSelector);
|
|
@@ -2921,9 +3278,10 @@ function installKeyboard(env) {
|
|
|
2921
3278
|
rovingKey = env.keyOf(mark);
|
|
2922
3279
|
env.select(mark, { ctrl: !!(e.ctrlKey || e.metaKey), shift: !!e.shiftKey });
|
|
2923
3280
|
break;
|
|
3281
|
+
// An inert chart's click on empty canvas clears nothing, so neither does its Escape.
|
|
2924
3282
|
case "Escape":
|
|
2925
3283
|
hideTip();
|
|
2926
|
-
if (env.escapeClears !== false) env.clear();
|
|
3284
|
+
if (env.escapeClears !== false && !env.inert()) env.clear();
|
|
2927
3285
|
break;
|
|
2928
3286
|
}
|
|
2929
3287
|
};
|
|
@@ -3399,77 +3757,13 @@ function createChartHost(container, config) {
|
|
|
3399
3757
|
};
|
|
3400
3758
|
const GLYPH_LAYER_CLASS = "bic-selection-glyphs";
|
|
3401
3759
|
let glyphPositionWas = null;
|
|
3402
|
-
|
|
3403
|
-
|
|
3404
|
-
|
|
3405
|
-
|
|
3406
|
-
|
|
3760
|
+
const glyphFollower = followMarks(container, {
|
|
3761
|
+
win,
|
|
3762
|
+
blind: `.${GLYPH_LAYER_CLASS}, .${LASSO_OUTLINE_CLASS}`,
|
|
3763
|
+
repaint: (resized) => paintGlyphLayer(resized ? "if-changed" : false)
|
|
3764
|
+
});
|
|
3407
3765
|
let glyphReported = "";
|
|
3408
|
-
const
|
|
3409
|
-
const glyphBlind = `.${GLYPH_LAYER_CLASS}, .${LASSO_OUTLINE_CLASS}`;
|
|
3410
|
-
const movesAMark = (r) => {
|
|
3411
|
-
const t = r.target;
|
|
3412
|
-
if (!t || t.closest?.(glyphBlind)) return false;
|
|
3413
|
-
return !!(t.classList?.contains(MARK_CLASS) || t.querySelector?.(`.${MARK_CLASS}`));
|
|
3414
|
-
};
|
|
3415
|
-
const queueGlyphs = (reportIfChanged) => {
|
|
3416
|
-
if (reportIfChanged) glyphQueuedReport = true;
|
|
3417
|
-
if (glyphQueued) return;
|
|
3418
|
-
glyphQueued = true;
|
|
3419
|
-
const run = () => {
|
|
3420
|
-
const r = glyphQueuedReport;
|
|
3421
|
-
glyphQueued = false;
|
|
3422
|
-
glyphQueuedReport = false;
|
|
3423
|
-
if (glyphObserver || glyphResize) paintGlyphLayer(r ? "if-changed" : false);
|
|
3424
|
-
};
|
|
3425
|
-
if (win?.requestAnimationFrame) win.requestAnimationFrame(run);
|
|
3426
|
-
else setTimeout(run, 16);
|
|
3427
|
-
};
|
|
3428
|
-
const followGlyphs = (on) => {
|
|
3429
|
-
if (!on) {
|
|
3430
|
-
if (glyphObserver) {
|
|
3431
|
-
glyphObserver.disconnect();
|
|
3432
|
-
glyphObserver = null;
|
|
3433
|
-
}
|
|
3434
|
-
if (glyphResize) {
|
|
3435
|
-
glyphResize.disconnect();
|
|
3436
|
-
glyphResize = null;
|
|
3437
|
-
}
|
|
3438
|
-
return;
|
|
3439
|
-
}
|
|
3440
|
-
const MO = win?.MutationObserver;
|
|
3441
|
-
if (!glyphObserver && MO) {
|
|
3442
|
-
glyphObserver = new MO((records) => {
|
|
3443
|
-
if (!glyphQueued && records.some(movesAMark)) queueGlyphs(false);
|
|
3444
|
-
});
|
|
3445
|
-
glyphObserver.observe(container, {
|
|
3446
|
-
subtree: true,
|
|
3447
|
-
attributes: true,
|
|
3448
|
-
attributeFilter: [
|
|
3449
|
-
"transform",
|
|
3450
|
-
"d",
|
|
3451
|
-
"x",
|
|
3452
|
-
"y",
|
|
3453
|
-
"cx",
|
|
3454
|
-
"cy",
|
|
3455
|
-
"points",
|
|
3456
|
-
"width",
|
|
3457
|
-
"height",
|
|
3458
|
-
"visibility",
|
|
3459
|
-
"opacity",
|
|
3460
|
-
"style",
|
|
3461
|
-
"class"
|
|
3462
|
-
]
|
|
3463
|
-
});
|
|
3464
|
-
}
|
|
3465
|
-
const RO = win?.ResizeObserver;
|
|
3466
|
-
if (!glyphResize && RO) {
|
|
3467
|
-
glyphResize = new RO(() => {
|
|
3468
|
-
if (sizeOfContainer() !== glyphSize) queueGlyphs(true);
|
|
3469
|
-
});
|
|
3470
|
-
glyphResize.observe(container);
|
|
3471
|
-
}
|
|
3472
|
-
};
|
|
3766
|
+
const followGlyphs = (on) => glyphFollower.follow(on);
|
|
3473
3767
|
const markShown = (m) => {
|
|
3474
3768
|
try {
|
|
3475
3769
|
const cv = m.checkVisibility;
|
|
@@ -3518,8 +3812,13 @@ function createChartHost(container, config) {
|
|
|
3518
3812
|
try {
|
|
3519
3813
|
let layer = container.querySelector(`:scope > .${GLYPH_LAYER_CLASS}`);
|
|
3520
3814
|
clearSelectionGlyphs(layer);
|
|
3521
|
-
const mode =
|
|
3522
|
-
|
|
3815
|
+
const mode = selectionMarkerFor({
|
|
3816
|
+
choice: resolved.selectionMarker,
|
|
3817
|
+
mapChoice: resolved.mapSelectionMarker,
|
|
3818
|
+
regionMap: isRegionMapData(data),
|
|
3819
|
+
neutralCentreRamp: hasNeutralCentreRamp(container)
|
|
3820
|
+
});
|
|
3821
|
+
if (mode !== "dot" && mode !== "check" && mode !== "outline") {
|
|
3523
3822
|
glyphReported = "";
|
|
3524
3823
|
return;
|
|
3525
3824
|
}
|
|
@@ -3567,20 +3866,41 @@ function createChartHost(container, config) {
|
|
|
3567
3866
|
const sw = container.scrollWidth || 0, sh = container.scrollHeight || 0;
|
|
3568
3867
|
layer.style.width = `${sw}px`;
|
|
3569
3868
|
layer.style.height = `${sh}px`;
|
|
3570
|
-
|
|
3571
|
-
const centers = [];
|
|
3572
|
-
collectGlyphCentersWhere(container, layer.getBoundingClientRect(), centers, { shown: markShown, at: glyphWindows() });
|
|
3869
|
+
glyphFollower.painted();
|
|
3573
3870
|
const hc = !!resolved.isHighContrast;
|
|
3574
|
-
|
|
3575
|
-
|
|
3576
|
-
|
|
3577
|
-
|
|
3578
|
-
|
|
3579
|
-
|
|
3871
|
+
let drawn = 0, total = 0;
|
|
3872
|
+
if (mode === "outline") {
|
|
3873
|
+
const marks = collectOutlineMarks(container, { shown: markShown });
|
|
3874
|
+
total = marks.length;
|
|
3875
|
+
let ink = resolved.themeFg || "";
|
|
3876
|
+
if (!ink) {
|
|
3877
|
+
try {
|
|
3878
|
+
ink = win?.getComputedStyle?.(container)?.color || "";
|
|
3879
|
+
} catch {
|
|
3880
|
+
ink = "";
|
|
3881
|
+
}
|
|
3882
|
+
}
|
|
3883
|
+
drawn = total ? paintSelectionOutlines(layer, marks, {
|
|
3884
|
+
color: ink || "#111",
|
|
3885
|
+
halo: resolved.themeBg || (hc ? "#000" : "#fff"),
|
|
3886
|
+
windowOf: (m) => outlineWindowOf(m, container),
|
|
3887
|
+
avoid: controlBoxesIn(container)
|
|
3888
|
+
}) : 0;
|
|
3889
|
+
} else {
|
|
3890
|
+
const centers = [];
|
|
3891
|
+
collectGlyphCentersWhere(container, layer.getBoundingClientRect(), centers, { shown: markShown, at: glyphWindows() });
|
|
3892
|
+
total = centers.length;
|
|
3893
|
+
drawn = centers.length ? paintSelectionGlyphs(layer, centers, {
|
|
3894
|
+
symbol: mode === "check" ? "\u2713" : "\u25CF",
|
|
3895
|
+
color: hc ? resolved.themeFg || "#111" : "#111",
|
|
3896
|
+
halo: hc ? resolved.themeBg || "#fff" : "#fff"
|
|
3897
|
+
}) : 0;
|
|
3898
|
+
}
|
|
3899
|
+
const said = `${mode}:${drawn}:${total}`;
|
|
3580
3900
|
if (report === true || report === "if-changed" && said !== glyphReported) {
|
|
3581
3901
|
glyphReported = said;
|
|
3582
3902
|
try {
|
|
3583
|
-
config.onSelectionGlyphs?.({ mode, drawn, total
|
|
3903
|
+
config.onSelectionGlyphs?.({ mode, drawn, total, suppressed: false });
|
|
3584
3904
|
} catch {
|
|
3585
3905
|
}
|
|
3586
3906
|
}
|
|
@@ -3588,7 +3908,7 @@ function createChartHost(container, config) {
|
|
|
3588
3908
|
} finally {
|
|
3589
3909
|
try {
|
|
3590
3910
|
followGlyphs(follow);
|
|
3591
|
-
|
|
3911
|
+
glyphFollower.takeRecords();
|
|
3592
3912
|
} catch {
|
|
3593
3913
|
}
|
|
3594
3914
|
}
|
|
@@ -3716,7 +4036,15 @@ function createChartHost(container, config) {
|
|
|
3716
4036
|
{ ctrl: !!(e?.ctrlKey || e?.metaKey), shift: !!e?.shiftKey }
|
|
3717
4037
|
));
|
|
3718
4038
|
const fromLabel = !!tick && !multi && !toggledOff && !chartOwnsTimeline(container);
|
|
3719
|
-
|
|
4039
|
+
const fromMark = !tick && !multi && !toggledOff;
|
|
4040
|
+
notify(
|
|
4041
|
+
next,
|
|
4042
|
+
"user",
|
|
4043
|
+
toggledOff ? null : tick,
|
|
4044
|
+
false,
|
|
4045
|
+
true,
|
|
4046
|
+
fromLabel ? { fromLabel: true } : fromMark ? { fromMark: true } : void 0
|
|
4047
|
+
);
|
|
3720
4048
|
};
|
|
3721
4049
|
container.addEventListener(XFILTER_REFRESH_EVENT, onXf);
|
|
3722
4050
|
const untrackPress = trackPress(container);
|
|
@@ -4390,6 +4718,21 @@ export {
|
|
|
4390
4718
|
autoRampMinStep,
|
|
4391
4719
|
autoRampCanvas,
|
|
4392
4720
|
resolveAutoColorScale,
|
|
4721
|
+
SELECTION_MARKER_DEFAULT,
|
|
4722
|
+
MAP_SELECTION_MARKER_DEFAULT,
|
|
4723
|
+
readSelectionMarker,
|
|
4724
|
+
readMapSelectionMarker,
|
|
4725
|
+
REGION_JOIN_COLUMN,
|
|
4726
|
+
isRegionMapData,
|
|
4727
|
+
NEUTRAL_CENTRE_RAMP_SELECTOR,
|
|
4728
|
+
hasNeutralCentreRamp,
|
|
4729
|
+
selectionMarkerFor,
|
|
4730
|
+
SELECTION_OUTLINE_CLASS,
|
|
4731
|
+
isAreaMark,
|
|
4732
|
+
collectOutlineMarks,
|
|
4733
|
+
outlineWindowOf,
|
|
4734
|
+
controlBoxesIn,
|
|
4735
|
+
paintSelectionOutlines,
|
|
4393
4736
|
EXPORT_FORMATS,
|
|
4394
4737
|
XLSX_MIME,
|
|
4395
4738
|
CSV_MIME,
|
|
@@ -4409,6 +4752,8 @@ export {
|
|
|
4409
4752
|
resolveOptions,
|
|
4410
4753
|
buildRenderPayload,
|
|
4411
4754
|
stripJsComments,
|
|
4755
|
+
MARK_MOVE_ATTRIBUTES,
|
|
4756
|
+
followMarks,
|
|
4412
4757
|
censusMarks,
|
|
4413
4758
|
isBlankRender,
|
|
4414
4759
|
blankRenderFlag,
|