@bicharts/chart-host 0.6.83 → 0.6.85

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.
@@ -0,0 +1,198 @@
1
+ /*! @bicharts/chart-host — Apache-2.0. Bundled reference data: GeoNames (https://www.geonames.org/) CC BY 4.0; Natural Earth and US Census/TIGER (public domain). Full text: NOTICE in this package. */
2
+ import {
3
+ AXIS_FILTER_CLASS,
4
+ LEGEND_MARK_CLASS,
5
+ MARK_CLASS,
6
+ ROW_IDX_ATTR
7
+ } from "./chunk-MR6TL7QZ.mjs";
8
+
9
+ // src/hitTargets.ts
10
+ var SVG_NS = "http://www.w3.org/2000/svg";
11
+ var HIT_ATTR = "data-lch-hit";
12
+ var ELEMENT_CAP = 5e3;
13
+ var mapsPresentationAttributes = /* @__PURE__ */ new WeakMap();
14
+ function engineMapsPresentationAttributes(ownerDoc, view) {
15
+ if (!ownerDoc || typeof ownerDoc !== "object") return false;
16
+ const known = mapsPresentationAttributes.get(ownerDoc);
17
+ if (known !== void 0) return known;
18
+ let maps = false;
19
+ try {
20
+ const host = ownerDoc.documentElement;
21
+ const probe = ownerDoc.createElementNS(SVG_NS, "svg");
22
+ const shape = ownerDoc.createElementNS(SVG_NS, "rect");
23
+ shape.setAttribute("fill", "none");
24
+ probe.appendChild(shape);
25
+ host.appendChild(probe);
26
+ try {
27
+ maps = String(view.getComputedStyle(shape).fill ?? "").trim().toLowerCase() === "none";
28
+ } finally {
29
+ host.removeChild(probe);
30
+ }
31
+ } catch {
32
+ maps = false;
33
+ }
34
+ mapsPresentationAttributes.set(ownerDoc, maps);
35
+ return maps;
36
+ }
37
+ function ensureCrossfilterHitTargets(container, doc) {
38
+ const report = { tagged: 0, hitRects: 0, peFlips: 0, peStrokeOnly: 0 };
39
+ try {
40
+ if (!container || typeof container.querySelectorAll !== "function") return report;
41
+ const els = container.querySelectorAll(
42
+ `.${MARK_CLASS}, .${LEGEND_MARK_CLASS}, .${AXIS_FILTER_CLASS}`
43
+ );
44
+ report.tagged = els.length;
45
+ if (els.length === 0 || els.length > ELEMENT_CAP) return report;
46
+ const ownerDoc = doc ?? container.ownerDocument;
47
+ const view = ownerDoc?.defaultView;
48
+ const computed = (el) => {
49
+ try {
50
+ return view?.getComputedStyle ? view.getComputedStyle(el) : null;
51
+ } catch {
52
+ return null;
53
+ }
54
+ };
55
+ for (const el of Array.from(els)) {
56
+ const tag = String(el.tagName || "").toLowerCase();
57
+ if (tag === "g") {
58
+ if (!el.hasAttribute?.(ROW_IDX_ATTR)) continue;
59
+ if (el.querySelector?.(`rect[${HIT_ATTR}="1"]`)) continue;
60
+ const cls = el.getAttribute?.("class") || "";
61
+ const isFurniture = cls.indexOf(LEGEND_MARK_CLASS) >= 0 || cls.indexOf(AXIS_FILTER_CLASS) >= 0;
62
+ if (!isFurniture) {
63
+ let hasHittableChild = false;
64
+ const kids = el.querySelectorAll?.("*") ?? [];
65
+ for (const kid of Array.from(kids)) {
66
+ const ktag = String(kid.tagName || "").toLowerCase();
67
+ if (ktag === "g" || ktag === "tspan" || ktag === "title" || ktag === "defs") continue;
68
+ const cs = computed(kid);
69
+ if (!cs || cs.pointerEvents !== "none") {
70
+ hasHittableChild = true;
71
+ break;
72
+ }
73
+ }
74
+ if (hasHittableChild) continue;
75
+ }
76
+ let bb = null;
77
+ try {
78
+ bb = el.getBBox?.();
79
+ } catch {
80
+ bb = null;
81
+ }
82
+ if (!bb || !(bb.width > 0) || !(bb.height > 0)) continue;
83
+ const rect = ownerDoc.createElementNS(SVG_NS, "rect");
84
+ rect.setAttribute("x", String(bb.x));
85
+ rect.setAttribute("y", String(bb.y));
86
+ rect.setAttribute("width", String(bb.width));
87
+ rect.setAttribute("height", String(bb.height));
88
+ rect.setAttribute("fill", "transparent");
89
+ rect.setAttribute(HIT_ATTR, "1");
90
+ if (rect.style) {
91
+ rect.style.pointerEvents = "all";
92
+ rect.style.cursor = "pointer";
93
+ }
94
+ el.insertBefore(rect, el.firstChild);
95
+ report.hitRects++;
96
+ } else {
97
+ const cs = computed(el);
98
+ if (cs && cs.pointerEvents === "none") {
99
+ const fill = String((engineMapsPresentationAttributes(ownerDoc, view) ? cs.fill : el.getAttribute?.("fill") ?? cs.fill) ?? "").trim().toLowerCase();
100
+ const unfilled = fill === "none" || fill === "transparent" || fill === "rgba(0, 0, 0, 0)";
101
+ if (el.style) el.style.pointerEvents = unfilled ? "stroke" : "all";
102
+ report.peFlips++;
103
+ if (unfilled) report.peStrokeOnly++;
104
+ }
105
+ }
106
+ }
107
+ } catch {
108
+ }
109
+ return report;
110
+ }
111
+
112
+ // src/hitBands.ts
113
+ var MIN_HIT_BAND_PX = 8;
114
+ var ELEMENT_CAP2 = 5e3;
115
+ var EMPTY = {
116
+ openStrokes: 0,
117
+ interactive: 0,
118
+ hairline: 0,
119
+ uncovered: 0,
120
+ widestPx: 0
121
+ };
122
+ var OPEN_TAGS = /* @__PURE__ */ new Set(["path", "line", "polyline"]);
123
+ function styleOf(el, doc) {
124
+ try {
125
+ const view = doc?.defaultView;
126
+ return view?.getComputedStyle ? view.getComputedStyle(el) : null;
127
+ } catch {
128
+ return null;
129
+ }
130
+ }
131
+ function attrOrComputed(el, name, cs) {
132
+ const a = el.getAttribute?.(name);
133
+ if (a !== null && a !== void 0 && String(a).trim() !== "") return String(a).trim();
134
+ const c = cs?.[name === "stroke-width" ? "strokeWidth" : name];
135
+ return c === null || c === void 0 ? "" : String(c).trim();
136
+ }
137
+ function isUnfilled(fill) {
138
+ const f = fill.toLowerCase();
139
+ return f === "none" || f === "transparent" || f === "rgba(0, 0, 0, 0)" || f === "rgba(0,0,0,0)";
140
+ }
141
+ function widthPx(raw) {
142
+ const m = /^(-?\d+(?:\.\d+)?)\s*(px)?$/i.exec(raw);
143
+ if (!m) return NaN;
144
+ const n = parseFloat(m[1]);
145
+ return isFinite(n) ? n : NaN;
146
+ }
147
+ function censusHitBands(container, doc) {
148
+ if (!container || typeof container.querySelectorAll !== "function") return EMPTY;
149
+ try {
150
+ const els = Array.from(
151
+ container.querySelectorAll(`.${MARK_CLASS}, [${ROW_IDX_ATTR}]`)
152
+ );
153
+ if (els.length === 0 || els.length > ELEMENT_CAP2) return EMPTY;
154
+ const ownerDoc = doc ?? container.ownerDocument;
155
+ const widestByGeom = /* @__PURE__ */ new Map();
156
+ const rows = [];
157
+ for (const el of els) {
158
+ const tag = String(el.tagName || "").toLowerCase();
159
+ if (!OPEN_TAGS.has(tag)) continue;
160
+ const cs = styleOf(el, ownerDoc);
161
+ const open = isUnfilled(attrOrComputed(el, "fill", cs));
162
+ const w = widthPx(attrOrComputed(el, "stroke-width", cs) || "1");
163
+ const geom = String(el.getAttribute?.("d") ?? "") || `${tag}#${String(el.getAttribute?.(ROW_IDX_ATTR) ?? "")}`;
164
+ const inert = String(cs?.pointerEvents ?? el.style?.pointerEvents ?? "") === "none";
165
+ rows.push({ el, geom, w, open, inert });
166
+ if (isFinite(w)) {
167
+ const prev = widestByGeom.get(geom);
168
+ if (prev === void 0 || w > prev) widestByGeom.set(geom, w);
169
+ }
170
+ }
171
+ const out = { ...EMPTY };
172
+ for (const r of rows) {
173
+ if (!r.open) continue;
174
+ out.openStrokes++;
175
+ if (r.inert) continue;
176
+ out.interactive++;
177
+ if (isFinite(r.w) && r.w > out.widestPx) out.widestPx = Math.round(r.w);
178
+ if (!(r.w < MIN_HIT_BAND_PX)) continue;
179
+ out.hairline++;
180
+ const best = widestByGeom.get(r.geom);
181
+ if (best === void 0 || best < MIN_HIT_BAND_PX) out.uncovered++;
182
+ }
183
+ return out;
184
+ } catch {
185
+ return EMPTY;
186
+ }
187
+ }
188
+ function hitBandFlag(c) {
189
+ if (c.interactive === 0) return "";
190
+ return c.uncovered > 0 ? "hitband:d3:thin" : "hitband:d3:ok";
191
+ }
192
+
193
+ export {
194
+ ensureCrossfilterHitTargets,
195
+ MIN_HIT_BAND_PX,
196
+ censusHitBands,
197
+ hitBandFlag
198
+ };