@bicharts/chart-host 0.6.115 → 0.6.116
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 +18 -0
- package/dist/adapters.mjs +3 -3
- package/dist/card.mjs +2 -2
- package/dist/category-colours.mjs +275 -0
- package/dist/{chunk-AQO4ROMU.mjs → chunk-63IUMWY2.mjs} +40 -3
- package/dist/{chunk-YOCYWON4.mjs → chunk-EFKGSDFF.mjs} +1 -1
- package/dist/{chunk-7K3F3RZ6.mjs → chunk-GZSYTDFN.mjs} +68 -275
- package/dist/{chunk-QLIRQJ6B.mjs → chunk-IW6BKFF5.mjs} +1 -1
- package/dist/{chunk-YSRMSDRP.mjs → chunk-JMLSNV5Q.mjs} +1 -1
- package/dist/chunk-JTZTTJJK.mjs +244 -0
- package/dist/{chunk-VPFP35XI.mjs → chunk-K2TH7D5V.mjs} +299 -299
- package/dist/{chunk-GXR7T6G5.mjs → chunk-QG5TENI3.mjs} +4 -0
- package/dist/{chunk-PQKLWYKK.mjs → chunk-RLOIA7QK.mjs} +1 -1
- package/dist/{chunk-CVTCR7HQ.mjs → chunk-TUZCM7SX.mjs} +2 -2
- package/dist/{chunk-DILJDN6C.mjs → chunk-VGJH63LZ.mjs} +1 -1
- package/dist/{chunk-2GW3S5VD.mjs → chunk-ZZBX5ZJ6.mjs} +15 -2
- package/dist/dax.mjs +23 -1
- package/dist/index.mjs +63 -16
- package/dist/legend-fit.mjs +3 -3
- package/dist/page.mjs +5 -5
- package/dist/provinces.mjs +4 -4
- package/dist/react.mjs +12 -11
- package/dist/testing.mjs +1 -1
- package/dist/types/categoryColours.d.ts +71 -0
- package/dist/types/contract.d.ts +2 -0
- package/dist/types/dax.d.ts +26 -0
- package/dist/types/filterScope.d.ts +10 -1
- package/dist/types/fit.d.ts +6 -1
- package/dist/types/fitDom.d.ts +13 -0
- package/dist/types/host.d.ts +10 -0
- package/dist/types/index.d.ts +4 -3
- package/dist/types/qualifyTable.d.ts +52 -0
- package/dist/zoom-memory.mjs +1 -1
- package/package.json +6 -1
- /package/dist/{chunk-5YSZABCS.mjs → chunk-LXTW6YII.mjs} +0 -0
package/README.md
CHANGED
|
@@ -137,6 +137,21 @@ nothing to the line, since that query keeps every row. A bare filter, `{ filter
|
|
|
137
137
|
key column says the whole key. `label` sets what the line calls the filter. Outside React, `filterScopeOf` from
|
|
138
138
|
`@bicharts/chart-host/page` takes the same list and returns `options.filterScope`.
|
|
139
139
|
|
|
140
|
+
### A query that feeds no chart
|
|
141
|
+
|
|
142
|
+
A form's choice list, a lookup or a count beside a chart reads its query's rows by column name. A DAX result names
|
|
143
|
+
its columns `Table[Column]` and its measures `[Measure]`; `queryRows` from `@bicharts/chart-host/dax` returns each row
|
|
144
|
+
keyed by the bare name. Never parse the headers by hand: a pattern written through a shell and a script can lose its
|
|
145
|
+
backslashes on the way to disk and leave every value blank while the app's tests pass.
|
|
146
|
+
|
|
147
|
+
```tsx
|
|
148
|
+
const owners = queryRows(useSemanticModelQuery({ connection, query: OWNERS_DAX }).data);
|
|
149
|
+
owners.map(r => r["Sales owner"]); // Owners[Sales owner]
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
Two columns with one bare name (`Accounts[Name]` and `Owners[Name]`) keep their whole headers. `columnName(header)`
|
|
153
|
+
gives one header's bare name.
|
|
154
|
+
|
|
140
155
|
### Several panels that pick the same key
|
|
141
156
|
|
|
142
157
|
A map, a table and a scatter that each pick a country are ONE pick. Give their filters one `group`, and keep each
|
|
@@ -156,6 +171,9 @@ whichever panel shows it clears it, and the panel the reader picked in keeps all
|
|
|
156
171
|
open items for the picked countries) reads the members' keys, which are that one pick. Without `group` the filters
|
|
157
172
|
are separate picks, ANDed: a country picked on the map and then in the table is held twice, and clicking it again on
|
|
158
173
|
the map leaves the page filtered by the table's. Outside React, `scope.filter(column, { group })` does the same.
|
|
174
|
+
A saved view or a link (`useBicUrlState`) names each member on its own (`Country`, `Country-2`, `Country-3`, in the
|
|
175
|
+
order the page makes them), so a lasso saved on the scatter comes back on the scatter; give a member `key` for a name
|
|
176
|
+
that doesn't depend on that order.
|
|
159
177
|
|
|
160
178
|
## Vanilla
|
|
161
179
|
|
package/dist/adapters.mjs
CHANGED
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
censusHitBands,
|
|
4
4
|
ensureCrossfilterHitTargets,
|
|
5
5
|
hitBandFlag
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-EFKGSDFF.mjs";
|
|
7
7
|
import {
|
|
8
8
|
clickWasDrag,
|
|
9
9
|
collectD3GlyphCenters,
|
|
@@ -12,13 +12,13 @@ import {
|
|
|
12
12
|
markKeyOf,
|
|
13
13
|
rowIdxsFromMark,
|
|
14
14
|
selectionRuleOf
|
|
15
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-RLOIA7QK.mjs";
|
|
16
16
|
import {
|
|
17
17
|
AXIS_FILTER_CLASS,
|
|
18
18
|
LEGEND_MARK_CLASS,
|
|
19
19
|
MARK_CLASS,
|
|
20
20
|
ROW_IDX_ATTR
|
|
21
|
-
} from "./chunk-
|
|
21
|
+
} from "./chunk-QG5TENI3.mjs";
|
|
22
22
|
import "./chunk-GHODWOAL.mjs";
|
|
23
23
|
|
|
24
24
|
// src/adapters/types.ts
|
package/dist/card.mjs
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/*! @bicharts/chart-host — Apache-2.0. Bundled reference data: GeoNames (https://www.geonames.org/) CC BY 4.0; Natural Earth and US Census/TIGER (public domain). Full text: NOTICE in this package. */
|
|
2
2
|
import {
|
|
3
3
|
computeSelectionCard
|
|
4
|
-
} from "./chunk-
|
|
5
|
-
import "./chunk-
|
|
4
|
+
} from "./chunk-JMLSNV5Q.mjs";
|
|
5
|
+
import "./chunk-K2TH7D5V.mjs";
|
|
6
6
|
import "./chunk-GHODWOAL.mjs";
|
|
7
7
|
|
|
8
8
|
// src/selectionCardChrome.ts
|
|
@@ -0,0 +1,275 @@
|
|
|
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
|
+
MIN_RAMP_FILLS,
|
|
4
|
+
RAMP_SLACK_MAX,
|
|
5
|
+
deltaE2000,
|
|
6
|
+
hexToLab,
|
|
7
|
+
rgbToLab
|
|
8
|
+
} from "./chunk-JTZTTJJK.mjs";
|
|
9
|
+
import {
|
|
10
|
+
CATEGORY_DELTA_E_FLOOR,
|
|
11
|
+
DIM_OPACITY_DEFAULT,
|
|
12
|
+
LEGEND_MARK_CLASS,
|
|
13
|
+
MARK_CLASS,
|
|
14
|
+
ROW_IDX_ATTR
|
|
15
|
+
} from "./chunk-QG5TENI3.mjs";
|
|
16
|
+
import "./chunk-GHODWOAL.mjs";
|
|
17
|
+
|
|
18
|
+
// src/categoryColours.ts
|
|
19
|
+
var MAX_CATEGORY_SLOTS = 24;
|
|
20
|
+
var RAMP_DECLINE_MIN_SLOTS = 6;
|
|
21
|
+
var ELEMENT_CAP = 5e3;
|
|
22
|
+
var MAX_LISTED_PAIRS = 10;
|
|
23
|
+
function emptyCensus(declined, dimOpacity, slots = 0, source = "") {
|
|
24
|
+
return {
|
|
25
|
+
source,
|
|
26
|
+
declined,
|
|
27
|
+
slots,
|
|
28
|
+
closestPair: [],
|
|
29
|
+
closestDeltaE: null,
|
|
30
|
+
closestDeltaEPainted: null,
|
|
31
|
+
closestDeltaEDimmed: null,
|
|
32
|
+
dimOpacity,
|
|
33
|
+
rampLike: false,
|
|
34
|
+
legendMatchesMarks: null,
|
|
35
|
+
floor: CATEGORY_DELTA_E_FLOOR,
|
|
36
|
+
belowFloor: null,
|
|
37
|
+
pairsBelowFloorCount: 0,
|
|
38
|
+
pairsBelowFloor: [],
|
|
39
|
+
closestPairPainted: [],
|
|
40
|
+
closestDeltaEDeutan: null,
|
|
41
|
+
closestDeltaEProtan: null
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
function styleOf(el, doc) {
|
|
45
|
+
try {
|
|
46
|
+
const view = doc?.defaultView;
|
|
47
|
+
return view?.getComputedStyle ? view.getComputedStyle(el) : null;
|
|
48
|
+
} catch {
|
|
49
|
+
return null;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
function parsePaint(raw) {
|
|
53
|
+
if (raw === null || raw === void 0) return null;
|
|
54
|
+
const s = String(raw).trim().toLowerCase();
|
|
55
|
+
if (!s || s === "none" || s === "transparent" || s.startsWith("url(")) return null;
|
|
56
|
+
const hex = /^#([0-9a-f]{3}|[0-9a-f]{6})$/.exec(s);
|
|
57
|
+
if (hex) {
|
|
58
|
+
const h = hex[1].length === 3 ? hex[1].replace(/./g, (c) => c + c) : hex[1];
|
|
59
|
+
return { rgb: [parseInt(h.slice(0, 2), 16), parseInt(h.slice(2, 4), 16), parseInt(h.slice(4, 6), 16)], alpha: 1 };
|
|
60
|
+
}
|
|
61
|
+
const m = /^rgba?\(\s*([\d.]+)[\s,]+([\d.]+)[\s,]+([\d.]+)\s*(?:[,/]\s*([\d.]+%?)\s*)?\)$/.exec(s);
|
|
62
|
+
if (!m) return null;
|
|
63
|
+
let alpha = 1;
|
|
64
|
+
if (m[4] !== void 0) alpha = m[4].endsWith("%") ? parseFloat(m[4]) / 100 : parseFloat(m[4]);
|
|
65
|
+
if (!(alpha > 0)) return null;
|
|
66
|
+
return { rgb: [Math.round(+m[1]), Math.round(+m[2]), Math.round(+m[3])], alpha: Math.min(1, alpha) };
|
|
67
|
+
}
|
|
68
|
+
function numberOr1(v) {
|
|
69
|
+
if (v === null || v === void 0 || String(v).trim() === "") return 1;
|
|
70
|
+
const n = parseFloat(String(v));
|
|
71
|
+
return Number.isFinite(n) ? Math.max(0, Math.min(1, n)) : 1;
|
|
72
|
+
}
|
|
73
|
+
function ownOpacity(el, container) {
|
|
74
|
+
let a = 1;
|
|
75
|
+
for (let n = el; n && n !== container; n = n.parentNode) {
|
|
76
|
+
if (typeof n.getAttribute !== "function") break;
|
|
77
|
+
a *= numberOr1(n.getAttribute("opacity"));
|
|
78
|
+
a *= numberOr1(n.style?.opacity);
|
|
79
|
+
}
|
|
80
|
+
return a;
|
|
81
|
+
}
|
|
82
|
+
function paintOf(el, doc) {
|
|
83
|
+
const cs = styleOf(el, doc);
|
|
84
|
+
const fill = parsePaint(firstSet(el.getAttribute?.("fill"), el.style?.fill, cs?.fill));
|
|
85
|
+
if (fill) return { rgb: fill.rgb, alpha: fill.alpha * numberOr1(firstSet(el.getAttribute?.("fill-opacity"), el.style?.fillOpacity)) };
|
|
86
|
+
const stroke = parsePaint(firstSet(el.getAttribute?.("stroke"), el.style?.stroke, cs?.stroke));
|
|
87
|
+
if (stroke) return { rgb: stroke.rgb, alpha: stroke.alpha * numberOr1(firstSet(el.getAttribute?.("stroke-opacity"), el.style?.strokeOpacity)) };
|
|
88
|
+
return null;
|
|
89
|
+
}
|
|
90
|
+
function firstSet(...vals) {
|
|
91
|
+
for (const v of vals) if (v !== null && v !== void 0 && String(v).trim() !== "") return String(v);
|
|
92
|
+
return null;
|
|
93
|
+
}
|
|
94
|
+
function paintWithin(el, doc, container) {
|
|
95
|
+
let p = paintOf(el, doc);
|
|
96
|
+
let at = el;
|
|
97
|
+
if (!p && typeof el.querySelectorAll === "function") {
|
|
98
|
+
for (const child of Array.from(el.querySelectorAll("*"))) {
|
|
99
|
+
p = paintOf(child, doc);
|
|
100
|
+
if (p) {
|
|
101
|
+
at = child;
|
|
102
|
+
break;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
return p ? { rgb: p.rgb, alpha: p.alpha * ownOpacity(at, container) } : null;
|
|
107
|
+
}
|
|
108
|
+
var hexOf = (rgb) => "#" + rgb.map((v) => Math.max(0, Math.min(255, v)).toString(16).padStart(2, "0")).join("");
|
|
109
|
+
function blend(rgb, alpha, bg) {
|
|
110
|
+
const a = Math.max(0, Math.min(1, alpha));
|
|
111
|
+
return [rgb[0] * a + bg[0] * (1 - a), rgb[1] * a + bg[1] * (1 - a), rgb[2] * a + bg[2] * (1 - a)].map(Math.round);
|
|
112
|
+
}
|
|
113
|
+
function slotsOf(paints) {
|
|
114
|
+
const byColour = /* @__PURE__ */ new Map();
|
|
115
|
+
for (const p of paints) {
|
|
116
|
+
const k = p.rgb.join(",");
|
|
117
|
+
const slot = byColour.get(k) ?? { rgb: p.rgb, alphas: /* @__PURE__ */ new Map() };
|
|
118
|
+
const a = Math.round(p.alpha * 100) / 100;
|
|
119
|
+
slot.alphas.set(a, (slot.alphas.get(a) ?? 0) + 1);
|
|
120
|
+
byColour.set(k, slot);
|
|
121
|
+
}
|
|
122
|
+
return [...byColour.values()].map((s) => ({
|
|
123
|
+
rgb: s.rgb,
|
|
124
|
+
alpha: [...s.alphas].sort((x, y) => y[1] - x[1] || y[0] - x[0])[0][0]
|
|
125
|
+
}));
|
|
126
|
+
}
|
|
127
|
+
var MACHADO_DEUTAN = [[0.367322, 0.860646, -0.227968], [0.280085, 0.672501, 0.047413], [-0.01182, 0.04294, 0.968881]];
|
|
128
|
+
var MACHADO_PROTAN = [[0.152286, 1.052583, -0.204868], [0.114503, 0.786281, 0.099216], [-3882e-6, -0.048116, 1.051998]];
|
|
129
|
+
var toLinear = (c) => {
|
|
130
|
+
const v = c / 255;
|
|
131
|
+
return v <= 0.04045 ? v / 12.92 : Math.pow((v + 0.055) / 1.055, 2.4);
|
|
132
|
+
};
|
|
133
|
+
var toSrgb = (v) => {
|
|
134
|
+
const x = Math.max(0, Math.min(1, v));
|
|
135
|
+
return 255 * (x <= 31308e-7 ? 12.92 * x : 1.055 * Math.pow(x, 1 / 2.4) - 0.055);
|
|
136
|
+
};
|
|
137
|
+
function simulatedLab(rgb, m) {
|
|
138
|
+
const lin = rgb.map(toLinear);
|
|
139
|
+
const out = m.map((row) => toSrgb(row[0] * lin[0] + row[1] * lin[1] + row[2] * lin[2]));
|
|
140
|
+
return rgbToLab(out[0], out[1], out[2]);
|
|
141
|
+
}
|
|
142
|
+
function pairsUnder(labs, floor) {
|
|
143
|
+
const out = [];
|
|
144
|
+
for (let i = 0; i < labs.length; i++) {
|
|
145
|
+
for (let j = i + 1; j < labs.length; j++) {
|
|
146
|
+
const d = deltaE2000(labs[i], labs[j]);
|
|
147
|
+
if (d < floor) out.push({ i, j, d });
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
return out.sort((x, y) => x.d - y.d);
|
|
151
|
+
}
|
|
152
|
+
function closest(labs) {
|
|
153
|
+
let best = { i: 0, j: 1, d: Infinity };
|
|
154
|
+
for (let i = 0; i < labs.length; i++) {
|
|
155
|
+
for (let j = i + 1; j < labs.length; j++) {
|
|
156
|
+
const d = deltaE2000(labs[i], labs[j]);
|
|
157
|
+
if (d < best.d) best = { i, j, d };
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
return best;
|
|
161
|
+
}
|
|
162
|
+
function isRampShaped(labs) {
|
|
163
|
+
if (labs.length < MIN_RAMP_FILLS) return false;
|
|
164
|
+
let span = 0, lo = 0, hi = 1;
|
|
165
|
+
for (let i = 0; i < labs.length; i++) {
|
|
166
|
+
for (let j = i + 1; j < labs.length; j++) {
|
|
167
|
+
const v = deltaE2000(labs[i], labs[j]);
|
|
168
|
+
if (v > span) {
|
|
169
|
+
span = v;
|
|
170
|
+
lo = i;
|
|
171
|
+
hi = j;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
if (span <= 0) return false;
|
|
176
|
+
let slack = 0, interior = 0;
|
|
177
|
+
for (let i = 0; i < labs.length; i++) {
|
|
178
|
+
if (i === lo || i === hi) continue;
|
|
179
|
+
slack += (deltaE2000(labs[lo], labs[i]) + deltaE2000(labs[i], labs[hi])) / span - 1;
|
|
180
|
+
interior++;
|
|
181
|
+
}
|
|
182
|
+
return interior >= 2 && slack / interior <= RAMP_SLACK_MAX;
|
|
183
|
+
}
|
|
184
|
+
var LIGHTNESS_STEP_MIN = 1.5;
|
|
185
|
+
function lightnessFollowsPath(labs) {
|
|
186
|
+
let span = -1, lo = 0;
|
|
187
|
+
for (let i = 0; i < labs.length; i++) {
|
|
188
|
+
for (let j = i + 1; j < labs.length; j++) {
|
|
189
|
+
const v = deltaE2000(labs[i], labs[j]);
|
|
190
|
+
if (v > span) {
|
|
191
|
+
span = v;
|
|
192
|
+
lo = i;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
const order = labs.map((l) => ({ L: l.L, d: deltaE2000(labs[lo], l) })).sort((a, b) => a.d - b.d);
|
|
197
|
+
let turns = 0, dir = 0;
|
|
198
|
+
for (let k = 1; k < order.length; k++) {
|
|
199
|
+
const step = order[k].L - order[k - 1].L;
|
|
200
|
+
if (Math.abs(step) < LIGHTNESS_STEP_MIN) continue;
|
|
201
|
+
const sign = Math.sign(step);
|
|
202
|
+
if (dir !== 0 && sign !== dir) turns++;
|
|
203
|
+
dir = sign;
|
|
204
|
+
}
|
|
205
|
+
return turns <= 1;
|
|
206
|
+
}
|
|
207
|
+
var round1 = (n) => Math.round(n * 10) / 10;
|
|
208
|
+
function censusCategoryColours(container, doc, options = {}) {
|
|
209
|
+
const dimOpacity = typeof options.dimOpacity === "number" && options.dimOpacity >= 0 && options.dimOpacity <= 1 ? options.dimOpacity : DIM_OPACITY_DEFAULT;
|
|
210
|
+
if (!container || typeof container.querySelectorAll !== "function") return emptyCensus("none", dimOpacity);
|
|
211
|
+
try {
|
|
212
|
+
const ownerDoc = doc ?? container.ownerDocument;
|
|
213
|
+
const legendEls = Array.from(container.querySelectorAll(`.${LEGEND_MARK_CLASS}`));
|
|
214
|
+
const markEls = Array.from(container.querySelectorAll(`.${MARK_CLASS}, [${ROW_IDX_ATTR}]`)).filter((el) => !el.classList?.contains(LEGEND_MARK_CLASS));
|
|
215
|
+
if (legendEls.length + markEls.length > ELEMENT_CAP) return emptyCensus("too-many", dimOpacity);
|
|
216
|
+
const paintsOf = (els) => els.map((el) => paintWithin(el, ownerDoc, container)).filter((p) => p !== null);
|
|
217
|
+
const legendSlots = slotsOf(paintsOf(legendEls));
|
|
218
|
+
const markSlots = slotsOf(paintsOf(markEls));
|
|
219
|
+
const useLegend = legendSlots.length >= 2;
|
|
220
|
+
const slots = useLegend ? legendSlots : markSlots;
|
|
221
|
+
const source = useLegend ? "legend" : markSlots.length ? "marks" : "";
|
|
222
|
+
if (slots.length < 2) return emptyCensus("none", dimOpacity, slots.length, source);
|
|
223
|
+
if (slots.length > MAX_CATEGORY_SLOTS) return emptyCensus("too-many", dimOpacity, slots.length, source);
|
|
224
|
+
const labs = slots.map((s) => hexToLab(hexOf(s.rgb))).filter((l) => l !== null);
|
|
225
|
+
if (labs.length !== slots.length) return emptyCensus("none", dimOpacity, slots.length, source);
|
|
226
|
+
const rampLike = isRampShaped(labs);
|
|
227
|
+
if (rampLike && slots.length >= RAMP_DECLINE_MIN_SLOTS && lightnessFollowsPath(labs)) return { ...emptyCensus("ramp", dimOpacity, slots.length, source), rampLike };
|
|
228
|
+
const bgPaint = parsePaint(options.pageBg);
|
|
229
|
+
const bg = bgPaint ? blend(bgPaint.rgb, bgPaint.alpha, [255, 255, 255]) : [255, 255, 255];
|
|
230
|
+
const labsAt = (alphaOf) => slots.map((s) => hexToLab(hexOf(blend(s.rgb, alphaOf(s), bg))));
|
|
231
|
+
const full = closest(labs);
|
|
232
|
+
const paintedLabs = labsAt((s) => s.alpha);
|
|
233
|
+
const painted = closest(paintedLabs);
|
|
234
|
+
const dimmed = closest(labsAt((s) => s.alpha * dimOpacity));
|
|
235
|
+
const under = pairsUnder(paintedLabs, CATEGORY_DELTA_E_FLOOR);
|
|
236
|
+
const paintedRgb = slots.map((s) => blend(s.rgb, s.alpha, bg));
|
|
237
|
+
const deutan = closest(paintedRgb.map((c) => simulatedLab(c, MACHADO_DEUTAN)));
|
|
238
|
+
const protan = closest(paintedRgb.map((c) => simulatedLab(c, MACHADO_PROTAN)));
|
|
239
|
+
let legendMatchesMarks = null;
|
|
240
|
+
if (useLegend && markSlots.length > 0) {
|
|
241
|
+
const markColours = new Set(markSlots.map((s) => s.rgb.join(",")));
|
|
242
|
+
legendMatchesMarks = legendSlots.every((s) => markColours.has(s.rgb.join(",")));
|
|
243
|
+
}
|
|
244
|
+
return {
|
|
245
|
+
source,
|
|
246
|
+
declined: "",
|
|
247
|
+
slots: slots.length,
|
|
248
|
+
closestPair: [hexOf(slots[full.i].rgb), hexOf(slots[full.j].rgb)],
|
|
249
|
+
closestDeltaE: round1(full.d),
|
|
250
|
+
closestDeltaEPainted: round1(painted.d),
|
|
251
|
+
closestDeltaEDimmed: round1(dimmed.d),
|
|
252
|
+
dimOpacity,
|
|
253
|
+
rampLike,
|
|
254
|
+
legendMatchesMarks,
|
|
255
|
+
floor: CATEGORY_DELTA_E_FLOOR,
|
|
256
|
+
belowFloor: painted.d < CATEGORY_DELTA_E_FLOOR,
|
|
257
|
+
pairsBelowFloorCount: under.length,
|
|
258
|
+
pairsBelowFloor: under.slice(0, MAX_LISTED_PAIRS).map((p) => ({
|
|
259
|
+
colours: [hexOf(slots[p.i].rgb), hexOf(slots[p.j].rgb)],
|
|
260
|
+
deltaE: round1(p.d)
|
|
261
|
+
})),
|
|
262
|
+
closestPairPainted: [hexOf(slots[painted.i].rgb), hexOf(slots[painted.j].rgb)],
|
|
263
|
+
closestDeltaEDeutan: round1(deutan.d),
|
|
264
|
+
closestDeltaEProtan: round1(protan.d)
|
|
265
|
+
};
|
|
266
|
+
} catch {
|
|
267
|
+
return emptyCensus("none", dimOpacity);
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
export {
|
|
271
|
+
MAX_CATEGORY_SLOTS,
|
|
272
|
+
MAX_LISTED_PAIRS,
|
|
273
|
+
RAMP_DECLINE_MIN_SLOTS,
|
|
274
|
+
censusCategoryColours
|
|
275
|
+
};
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
/*! @bicharts/chart-host — Apache-2.0. Bundled reference data: GeoNames (https://www.geonames.org/) CC BY 4.0; Natural Earth and US Census/TIGER (public domain). Full text: NOTICE in this package. */
|
|
2
2
|
import {
|
|
3
3
|
CONTAINER_SLOT_SCROLL,
|
|
4
|
-
SNAPSHOT_SVG_ATTR
|
|
5
|
-
|
|
4
|
+
SNAPSHOT_SVG_ATTR,
|
|
5
|
+
TABLE_SCROLLER_CLASS
|
|
6
|
+
} from "./chunk-QG5TENI3.mjs";
|
|
6
7
|
|
|
7
8
|
// src/fit.ts
|
|
8
9
|
var SCROLL_SLACK_PX = 8;
|
|
@@ -273,10 +274,45 @@ function rememberScroll(container, key) {
|
|
|
273
274
|
if (slot[CONTAINER_SLOT_SCROLL]) return;
|
|
274
275
|
if (container.querySelector(".llm-mm-scroll")) return;
|
|
275
276
|
const x = container.scrollLeft, y = container.scrollTop;
|
|
276
|
-
|
|
277
|
+
const inner = innerScrollsOf(container);
|
|
278
|
+
if (x > 0 || y > 0 || inner) slot[CONTAINER_SLOT_SCROLL] = inner ? { key, x, y, inner } : { key, x, y };
|
|
277
279
|
} catch {
|
|
278
280
|
}
|
|
279
281
|
}
|
|
282
|
+
var INNER_SCROLLER_CAP = 16;
|
|
283
|
+
var offset = (n) => typeof n === "number" && isFinite(n) && n > 0 ? n : 0;
|
|
284
|
+
function innerScrollsOf(container) {
|
|
285
|
+
const els = container.querySelectorAll("." + TABLE_SCROLLER_CLASS);
|
|
286
|
+
if (!els.length) return null;
|
|
287
|
+
const out = [];
|
|
288
|
+
let any = false;
|
|
289
|
+
for (let i = 0; i < els.length && i < INNER_SCROLLER_CAP; i++) {
|
|
290
|
+
const el = els[i];
|
|
291
|
+
const x = offset(el.scrollLeft), y = offset(el.scrollTop);
|
|
292
|
+
if (x > 0 || y > 0) any = true;
|
|
293
|
+
out.push({ x, y });
|
|
294
|
+
}
|
|
295
|
+
return any ? out : null;
|
|
296
|
+
}
|
|
297
|
+
function restoreInnerScroll(container, memory, key) {
|
|
298
|
+
if (!container || !memory || !memory.inner || !memory.inner.length) return null;
|
|
299
|
+
if (key === void 0 || key === null || memory.key !== key) return null;
|
|
300
|
+
try {
|
|
301
|
+
const els = container.querySelectorAll("." + TABLE_SCROLLER_CLASS);
|
|
302
|
+
if (!els.length) return null;
|
|
303
|
+
const out = [];
|
|
304
|
+
for (let i = 0; i < els.length && i < memory.inner.length; i++) {
|
|
305
|
+
const el = els[i], want = memory.inner[i];
|
|
306
|
+
const x = offset(want && want.x), y = offset(want && want.y);
|
|
307
|
+
if (x > 0 && el.scrollLeft !== x) el.scrollLeft = x;
|
|
308
|
+
if (y > 0 && el.scrollTop !== y) el.scrollTop = y;
|
|
309
|
+
out.push({ x: offset(el.scrollLeft), y: offset(el.scrollTop) });
|
|
310
|
+
}
|
|
311
|
+
return out;
|
|
312
|
+
} catch {
|
|
313
|
+
return null;
|
|
314
|
+
}
|
|
315
|
+
}
|
|
280
316
|
function takeScroll(container) {
|
|
281
317
|
if (!container) return null;
|
|
282
318
|
try {
|
|
@@ -625,6 +661,7 @@ export {
|
|
|
625
661
|
fitReadingFor,
|
|
626
662
|
unpinScrolledAxis,
|
|
627
663
|
rememberScroll,
|
|
664
|
+
restoreInnerScroll,
|
|
628
665
|
takeScroll,
|
|
629
666
|
pinScrolledAxis,
|
|
630
667
|
fitRenderedChart
|