@bicharts/chart-host 0.5.89 → 0.5.91
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-NWMMNXH2.mjs → chunk-YIRWZUKN.mjs} +236 -37
- package/dist/index.mjs +9 -1
- package/dist/react.mjs +1 -1
- package/dist/types/colourSpread.d.ts +75 -0
- package/dist/types/deltaE.d.ts +24 -0
- package/dist/types/host.d.ts +16 -0
- package/dist/types/index.d.ts +1 -0
- package/package.json +1 -1
|
@@ -53,7 +53,7 @@ var require_papaparse_min = __commonJS({
|
|
|
53
53
|
q3(this._config.error) ? this._config.error(e2) : a4 && this._config.error && n.postMessage({ workerId: v3.WORKER_ID, error: e2, finished: false });
|
|
54
54
|
};
|
|
55
55
|
}
|
|
56
|
-
function
|
|
56
|
+
function f4(e) {
|
|
57
57
|
var r2;
|
|
58
58
|
(e = e || {}).chunkSize || (e.chunkSize = v3.RemoteChunkSize), u4.call(this, e), this._nextChunk = s2 ? function() {
|
|
59
59
|
this._readChunk(), this._chunkLoaded();
|
|
@@ -137,7 +137,7 @@ var require_papaparse_min = __commonJS({
|
|
|
137
137
|
}, this);
|
|
138
138
|
}
|
|
139
139
|
function i2(m2) {
|
|
140
|
-
var n2, s4, a5, t, o2 = Math.pow(2, 53), h3 = -o2, u5 = /^\s*-?(\d+\.?|\.\d+|\d+\.\d+)([eE][-+]?\d+)?\s*$/, d2 = /^((\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d\.\d+([+-][0-2]\d:[0-5]\d|Z))|(\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d([+-][0-2]\d:[0-5]\d|Z))|(\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d([+-][0-2]\d:[0-5]\d|Z)))$/, i4 = this, r2 = 0,
|
|
140
|
+
var n2, s4, a5, t, o2 = Math.pow(2, 53), h3 = -o2, u5 = /^\s*-?(\d+\.?|\.\d+|\d+\.\d+)([eE][-+]?\d+)?\s*$/, d2 = /^((\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d\.\d+([+-][0-2]\d:[0-5]\d|Z))|(\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d([+-][0-2]\d:[0-5]\d|Z))|(\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d([+-][0-2]\d:[0-5]\d|Z)))$/, i4 = this, r2 = 0, f5 = 0, l3 = false, e = false, c4 = [], p4 = { data: [], errors: [], meta: {} };
|
|
141
141
|
function y5(e2) {
|
|
142
142
|
return "greedy" === m2.skipEmptyLines ? "" === e2.join("").trim() : 1 === e2.length && 0 === e2[0].length;
|
|
143
143
|
}
|
|
@@ -164,10 +164,10 @@ var require_papaparse_min = __commonJS({
|
|
|
164
164
|
})(t5) ? parseFloat(t5) : d2.test(t5) ? new Date(t5) : "" === t5 ? null : t5) : t5)(n4 = m2.header ? r5 >= c4.length ? "__parsed_extra" : c4[r5] : n4, s5 = m2.transform ? m2.transform(s5, n4) : s5);
|
|
165
165
|
"__parsed_extra" === n4 ? (i6[n4] = i6[n4] || [], i6[n4].push(s5)) : i6[n4] = s5;
|
|
166
166
|
}
|
|
167
|
-
return m2.header && (r5 > c4.length ? k2("FieldMismatch", "TooManyFields", "Too many fields: expected " + c4.length + " fields but parsed " + r5,
|
|
167
|
+
return m2.header && (r5 > c4.length ? k2("FieldMismatch", "TooManyFields", "Too many fields: expected " + c4.length + " fields but parsed " + r5, f5 + t4) : r5 < c4.length && k2("FieldMismatch", "TooFewFields", "Too few fields: expected " + c4.length + " fields but parsed " + r5, f5 + t4)), i6;
|
|
168
168
|
}
|
|
169
169
|
var r4;
|
|
170
|
-
p4 && (m2.header || m2.dynamicTyping || m2.transform) && (r4 = 1, !p4.data.length || Array.isArray(p4.data[0]) ? (p4.data = p4.data.map(i5), r4 = p4.data.length) : p4.data = i5(p4.data, 0), m2.header && p4.meta && (p4.meta.fields = c4),
|
|
170
|
+
p4 && (m2.header || m2.dynamicTyping || m2.transform) && (r4 = 1, !p4.data.length || Array.isArray(p4.data[0]) ? (p4.data = p4.data.map(i5), r4 = p4.data.length) : p4.data = i5(p4.data, 0), m2.header && p4.meta && (p4.meta.fields = c4), f5 += r4);
|
|
171
171
|
}
|
|
172
172
|
function _3() {
|
|
173
173
|
return m2.header && 0 === c4.length;
|
|
@@ -183,8 +183,8 @@ var require_papaparse_min = __commonJS({
|
|
|
183
183
|
var s5, a6, o4, h4;
|
|
184
184
|
n4 = n4 || [",", " ", "|", ";", v3.RECORD_SEP, v3.UNIT_SEP];
|
|
185
185
|
for (var u6 = 0; u6 < n4.length; u6++) {
|
|
186
|
-
for (var d3,
|
|
187
|
-
0 < g5.data.length && (c5 /= g5.data.length - p5), (void 0 === a6 || l4 <= a6) && (void 0 === h4 || h4 < c5) && 1.99 < c5 && (a6 = l4, s5 =
|
|
186
|
+
for (var d3, f6 = n4[u6], l4 = 0, c5 = 0, p5 = 0, g5 = (o4 = void 0, new E4({ comments: r5, delimiter: f6, newline: t4, preview: 10 }).parse(e4)), _4 = 0; _4 < g5.data.length; _4++) i6 && y5(g5.data[_4]) ? p5++ : (d3 = g5.data[_4].length, c5 += d3, void 0 === o4 ? o4 = d3 : 0 < d3 && (l4 += Math.abs(d3 - o4), o4 = d3));
|
|
187
|
+
0 < g5.data.length && (c5 /= g5.data.length - p5), (void 0 === a6 || l4 <= a6) && (void 0 === h4 || h4 < c5) && 1.99 < c5 && (a6 = l4, s5 = f6, h4 = c5);
|
|
188
188
|
}
|
|
189
189
|
return { successful: !!(m2.delimiter = s5), bestDelimiter: s5 };
|
|
190
190
|
})(e2, m2.newline, m2.skipEmptyLines, m2.comments, m2.delimitersToGuess)).successful ? m2.delimiter = r4.bestDelimiter : (a5 = true, m2.delimiter = v3.DefaultDelimiter), p4.meta.delimiter = m2.delimiter), b2(m2));
|
|
@@ -217,7 +217,7 @@ var require_papaparse_min = __commonJS({
|
|
|
217
217
|
var z3 = 0, M = false;
|
|
218
218
|
this.parse = function(i4, t, r2) {
|
|
219
219
|
if ("string" != typeof i4) throw new Error("Input must be a string");
|
|
220
|
-
var n2 = i4.length, e = S.length, s4 = O2.length, a5 = x2.length, o2 = q3(I2), h3 = [], u5 = [], d2 = [],
|
|
220
|
+
var n2 = i4.length, e = S.length, s4 = O2.length, a5 = x2.length, o2 = q3(I2), h3 = [], u5 = [], d2 = [], f5 = z3 = 0;
|
|
221
221
|
if (!i4) return w2();
|
|
222
222
|
if (T3 || false !== T3 && -1 === i4.indexOf(F4)) {
|
|
223
223
|
for (var l3 = i4.split(O2), c4 = 0; c4 < l3.length; c4++) {
|
|
@@ -263,7 +263,7 @@ var require_papaparse_min = __commonJS({
|
|
|
263
263
|
}
|
|
264
264
|
return E5();
|
|
265
265
|
function k2(e2) {
|
|
266
|
-
h3.push(e2),
|
|
266
|
+
h3.push(e2), f5 = z3;
|
|
267
267
|
}
|
|
268
268
|
function v4(e2) {
|
|
269
269
|
var t2 = 0;
|
|
@@ -290,7 +290,7 @@ var require_papaparse_min = __commonJS({
|
|
|
290
290
|
}
|
|
291
291
|
n4 && console.warn("Duplicate headers found and renamed."), L2 = true;
|
|
292
292
|
}
|
|
293
|
-
return { data: h3, errors: u5, meta: { delimiter: S, linebreak: O2, aborted: M, truncated: !!e2, cursor:
|
|
293
|
+
return { data: h3, errors: u5, meta: { delimiter: S, linebreak: O2, aborted: M, truncated: !!e2, cursor: f5 + (t || 0), renamedHeaders: D3 } };
|
|
294
294
|
}
|
|
295
295
|
function R() {
|
|
296
296
|
I2(w2()), h3 = [], u5 = [];
|
|
@@ -339,7 +339,7 @@ var require_papaparse_min = __commonJS({
|
|
|
339
339
|
return v3.parse = function(e, t) {
|
|
340
340
|
var i4 = (t = t || {}).dynamicTyping || false;
|
|
341
341
|
q3(i4) && (t.dynamicTypingFunction = i4, i4 = {});
|
|
342
|
-
if (t.dynamicTyping = i4, t.transform = !!q3(t.transform) && t.transform, !t.worker || !v3.WORKERS_SUPPORTED) return i4 = null, v3.NODE_STREAM_INPUT, "string" == typeof e ? (e = P4(e), i4 = new (t.download ?
|
|
342
|
+
if (t.dynamicTyping = i4, t.transform = !!q3(t.transform) && t.transform, !t.worker || !v3.WORKERS_SUPPORTED) return i4 = null, v3.NODE_STREAM_INPUT, "string" == typeof e ? (e = P4(e), i4 = new (t.download ? f4 : c2)(t)) : true === e.readable && q3(e.read) && q3(e.on) ? i4 = new p2(t) : (n.File && e instanceof File || e instanceof Object) && (i4 = new l2(t)), i4.stream(e);
|
|
343
343
|
(i4 = (() => {
|
|
344
344
|
var e2;
|
|
345
345
|
return !!v3.WORKERS_SUPPORTED && (e2 = (() => {
|
|
@@ -374,11 +374,11 @@ var require_papaparse_min = __commonJS({
|
|
|
374
374
|
for (var o4 = 0; o4 < t2.length; o4++) {
|
|
375
375
|
var h4 = (n4 ? e2 : t2[o4]).length, u6 = false, d2 = n4 ? 0 === Object.keys(t2[o4]).length : 0 === t2[o4].length;
|
|
376
376
|
if (i5 && !n4 && (u6 = "greedy" === i5 ? "" === t2[o4].join("").trim() : 1 === t2[o4].length && 0 === t2[o4][0].length), "greedy" === i5 && n4) {
|
|
377
|
-
for (var
|
|
377
|
+
for (var f5 = [], l3 = 0; l3 < h4; l3++) {
|
|
378
378
|
var c4 = s5 ? e2[l3] : l3;
|
|
379
|
-
|
|
379
|
+
f5.push(t2[o4][c4]);
|
|
380
380
|
}
|
|
381
|
-
u6 = "" ===
|
|
381
|
+
u6 = "" === f5.join("").trim();
|
|
382
382
|
}
|
|
383
383
|
if (!u6) {
|
|
384
384
|
for (var p4 = 0; p4 < h4; p4++) {
|
|
@@ -398,7 +398,7 @@ var require_papaparse_min = __commonJS({
|
|
|
398
398
|
return false;
|
|
399
399
|
})(r4, v3.BAD_DELIMITERS) || -1 < r4.indexOf(m2) || -1 < i5.indexOf(a5) || " " === r4.charAt(0) || " " === r4.charAt(r4.length - 1)) ? a5 + r4 + a5 : r4);
|
|
400
400
|
}
|
|
401
|
-
}, v3.RECORD_SEP = String.fromCharCode(30), v3.UNIT_SEP = String.fromCharCode(31), v3.BYTE_ORDER_MARK = "\uFEFF", v3.BAD_DELIMITERS = ["\r", "\n", '"', v3.BYTE_ORDER_MARK], v3.WORKERS_SUPPORTED = !s2 && !!n.Worker, v3.NODE_STREAM_INPUT = 1, v3.LocalChunkSize = 10485760, v3.RemoteChunkSize = 5242880, v3.DefaultDelimiter = ",", v3.Parser = E4, v3.ParserHandle = i2, v3.NetworkStreamer =
|
|
401
|
+
}, v3.RECORD_SEP = String.fromCharCode(30), v3.UNIT_SEP = String.fromCharCode(31), v3.BYTE_ORDER_MARK = "\uFEFF", v3.BAD_DELIMITERS = ["\r", "\n", '"', v3.BYTE_ORDER_MARK], v3.WORKERS_SUPPORTED = !s2 && !!n.Worker, v3.NODE_STREAM_INPUT = 1, v3.LocalChunkSize = 10485760, v3.RemoteChunkSize = 5242880, v3.DefaultDelimiter = ",", v3.Parser = E4, v3.ParserHandle = i2, v3.NetworkStreamer = f4, v3.FileStreamer = l2, v3.StringStreamer = c2, v3.ReadableStreamStreamer = p2, n.jQuery && ((d = n.jQuery).fn.parse = function(o2) {
|
|
402
402
|
var i4 = o2.config || {}, h3 = [];
|
|
403
403
|
return this.each(function(e2) {
|
|
404
404
|
if (!("INPUT" === d(this).prop("tagName").toUpperCase() && "file" === d(this).attr("type").toLowerCase() && n.FileReader) || !this.files || 0 === this.files.length) return true;
|
|
@@ -429,7 +429,7 @@ var require_papaparse_min = __commonJS({
|
|
|
429
429
|
e = e.data;
|
|
430
430
|
void 0 === v3.WORKER_ID && e && (v3.WORKER_ID = e.workerId);
|
|
431
431
|
"string" == typeof e.input ? n.postMessage({ workerId: v3.WORKER_ID, results: v3.parse(e.input, e.config), finished: true }) : (n.File && e.input instanceof File || e.input instanceof Object) && (e = v3.parse(e.input, e.config)) && n.postMessage({ workerId: v3.WORKER_ID, results: e, finished: true });
|
|
432
|
-
}), (
|
|
432
|
+
}), (f4.prototype = Object.create(u4.prototype)).constructor = f4, (l2.prototype = Object.create(u4.prototype)).constructor = l2, (c2.prototype = Object.create(c2.prototype)).constructor = c2, (p2.prototype = Object.create(u4.prototype)).constructor = p2, v3;
|
|
433
433
|
});
|
|
434
434
|
}
|
|
435
435
|
});
|
|
@@ -630,7 +630,7 @@ function worldBasemap(world) {
|
|
|
630
630
|
if (!_worldBase) {
|
|
631
631
|
_worldBase = {
|
|
632
632
|
type: "FeatureCollection",
|
|
633
|
-
features: world.features.filter((
|
|
633
|
+
features: world.features.filter((f4) => f4?.geometry && f4.geometry.type !== "Point")
|
|
634
634
|
};
|
|
635
635
|
}
|
|
636
636
|
return _worldBase;
|
|
@@ -639,7 +639,7 @@ function northAmerica(world) {
|
|
|
639
639
|
if (!_na) {
|
|
640
640
|
_na = {
|
|
641
641
|
type: "FeatureCollection",
|
|
642
|
-
features: world.features.filter((
|
|
642
|
+
features: world.features.filter((f4) => NA_ISO3.has(f4?.id) && f4?.geometry && f4.geometry.type !== "Point").map((f4) => clipFeatureToLat(f4, NA_LAT_MAX)).filter((f4) => f4 !== null)
|
|
643
643
|
};
|
|
644
644
|
}
|
|
645
645
|
return _na;
|
|
@@ -900,10 +900,10 @@ function A3(n) {
|
|
|
900
900
|
}
|
|
901
901
|
let i2 = E(n.country), r = Y(n.state);
|
|
902
902
|
if (r && i2 && c3(r) !== i2 && (r = null), n.city !== void 0 && n.city !== null) {
|
|
903
|
-
let a4 = u(String(n.city)), s2 = O(a4),
|
|
904
|
-
if (
|
|
903
|
+
let a4 = u(String(n.city)), s2 = O(a4), f4 = s2 ? F(s2, n.mapKind) : null;
|
|
904
|
+
if (f4 && f4.length) {
|
|
905
905
|
let d = n.state === void 0 || n.state === null ? "" : String(n.state).trim(), R = d ? u(d) : "", g3 = d ? Y(d) : null, S = [], m = -1;
|
|
906
|
-
for (let c2 of
|
|
906
|
+
for (let c2 of f4) {
|
|
907
907
|
let l2 = c2.row, A = 0;
|
|
908
908
|
if (d && l2.a1 !== "") if (g3 && l2.a1 === g3 || u(l2.a1) === R) A++;
|
|
909
909
|
else continue;
|
|
@@ -938,7 +938,7 @@ function A3(n) {
|
|
|
938
938
|
var G = { latlon: 0, city: 1, zip3: 2, state: 3, country: 4 };
|
|
939
939
|
var x = 8;
|
|
940
940
|
function y3(n, e) {
|
|
941
|
-
let t = new Array(n.length), o = new Array(n.length), i2 = new Array(n.length), r = /* @__PURE__ */ new Set(), a4 = [], s2 = /* @__PURE__ */ new Set(),
|
|
941
|
+
let t = new Array(n.length), o = new Array(n.length), i2 = new Array(n.length), r = /* @__PURE__ */ new Set(), a4 = [], s2 = /* @__PURE__ */ new Set(), f4 = [], d = /* @__PURE__ */ new Set(), R = [], g3 = { latlon: 0, city: 0, zip3: 0, state: 0, country: 0 }, S = 0, m = 0, p2 = null;
|
|
942
942
|
for (let l2 = 0; l2 < n.length; ++l2) {
|
|
943
943
|
let A = n[l2], C2 = A3({ ...A, mapKind: e });
|
|
944
944
|
if (S3(C2)) {
|
|
@@ -948,7 +948,7 @@ function y3(n, e) {
|
|
|
948
948
|
} else if (C2) {
|
|
949
949
|
if (t[l2] = C2.lat, o[l2] = C2.lon, i2[l2] = C2.precision, S++, g3[C2.precision]++, (p2 === null || G[C2.precision] > G[p2]) && (p2 = C2.precision), G[C2.precision] > G.city) {
|
|
950
950
|
let M = K(A);
|
|
951
|
-
M && !s2.has(M.toLowerCase()) && (s2.add(M.toLowerCase()),
|
|
951
|
+
M && !s2.has(M.toLowerCase()) && (s2.add(M.toLowerCase()), f4.length < x && f4.push(M));
|
|
952
952
|
}
|
|
953
953
|
} else {
|
|
954
954
|
t[l2] = null, o[l2] = null, i2[l2] = null;
|
|
@@ -957,7 +957,7 @@ function y3(n, e) {
|
|
|
957
957
|
}
|
|
958
958
|
}
|
|
959
959
|
let c2 = !n3() && n.some((l2) => l2.city !== null && l2.city !== void 0 && String(l2.city).trim() !== "");
|
|
960
|
-
return { lat: t, lon: o, precisions: i2, precision: p2, precisionCounts: g3, coarseExamples:
|
|
960
|
+
return { lat: t, lon: o, precisions: i2, precision: p2, precisionCounts: g3, coarseExamples: f4, unmatched: a4, ambiguousRows: m, ambiguousExamples: R, matchedRows: S, totalRows: n.length, ...c2 ? { cityTableMissing: true } : {} };
|
|
961
961
|
}
|
|
962
962
|
function K(n) {
|
|
963
963
|
let e = [n.city, n.state, n.zip, n.country].filter((t) => t != null && String(t).trim() !== "").map((t) => String(t).trim()).join(", ");
|
|
@@ -1271,17 +1271,17 @@ function ie(r, n, e, s2, c2) {
|
|
|
1271
1271
|
for (let i2 of x2) {
|
|
1272
1272
|
let a4 = l2(i2);
|
|
1273
1273
|
if (P2(a4)) continue;
|
|
1274
|
-
let
|
|
1275
|
-
if (
|
|
1274
|
+
let f4 = v2(a4);
|
|
1275
|
+
if (f4 < 95) continue;
|
|
1276
1276
|
let N2 = z2(a4, (S) => !!Y(S)), Y2 = z2(a4, (S) => !!Y(S) && !q2(S, s2));
|
|
1277
|
-
N2 < E2 && Y2 < 1 || (!t ||
|
|
1277
|
+
N2 < E2 && Y2 < 1 || (!t || f4 > t.pct) && (t = { name: i2, pct: f4 });
|
|
1278
1278
|
}
|
|
1279
1279
|
t && (o.state = t.name, d.add(t.name), A.push(`state=${t.name} (${t.pct}% states/provinces)`));
|
|
1280
1280
|
}
|
|
1281
1281
|
if (!o.zip) for (let t of x2) {
|
|
1282
1282
|
if (d.has(t)) continue;
|
|
1283
1283
|
let i2 = l2(t), a4 = D2(i2);
|
|
1284
|
-
if (!(a4 < 95) && Z2(i2, t) && !(oe(i2, (
|
|
1284
|
+
if (!(a4 < 95) && Z2(i2, t) && !(oe(i2, (f4) => Z(f4).length > 0) < E2)) {
|
|
1285
1285
|
o.zip = t, d.add(t), A.push(`zip=${t} (${a4}% ZIP codes)`);
|
|
1286
1286
|
break;
|
|
1287
1287
|
}
|
|
@@ -1300,8 +1300,8 @@ function ie(r, n, e, s2, c2) {
|
|
|
1300
1300
|
let t = null;
|
|
1301
1301
|
for (let i2 of x2) {
|
|
1302
1302
|
if (d.has(i2)) continue;
|
|
1303
|
-
let a4 = l2(i2),
|
|
1304
|
-
|
|
1303
|
+
let a4 = l2(i2), f4 = ne(a4, s2);
|
|
1304
|
+
f4 < m3 || z2(a4, (N2) => p3(N2, s2)) < E2 || (!t || f4 > t.pct) && (t = { name: i2, pct: f4 });
|
|
1305
1305
|
}
|
|
1306
1306
|
t && (o.city = t.name, A.push(`city=${t.name} (${t.pct}% known cities)`));
|
|
1307
1307
|
}
|
|
@@ -1462,8 +1462,8 @@ function createMarkResolver(env) {
|
|
|
1462
1462
|
};
|
|
1463
1463
|
const isInvisibleStrokePath = (el) => {
|
|
1464
1464
|
if (el.tagName.toLowerCase() !== "path") return false;
|
|
1465
|
-
const
|
|
1466
|
-
if (
|
|
1465
|
+
const f4 = el.getAttribute("fill");
|
|
1466
|
+
if (f4 !== null && f4 !== "" && f4 !== "none" && f4 !== "transparent") return false;
|
|
1467
1467
|
const s2 = (el.getAttribute("stroke") || "").trim().toLowerCase();
|
|
1468
1468
|
const so = parseFloat(el.getAttribute("stroke-opacity") || "1");
|
|
1469
1469
|
return s2 === "transparent" || s2 === "none" || so <= 0.01;
|
|
@@ -1734,8 +1734,8 @@ function attrOrComputed(el, name, cs) {
|
|
|
1734
1734
|
return c2 === null || c2 === void 0 ? "" : String(c2).trim();
|
|
1735
1735
|
}
|
|
1736
1736
|
function isUnfilled(fill) {
|
|
1737
|
-
const
|
|
1738
|
-
return
|
|
1737
|
+
const f4 = fill.toLowerCase();
|
|
1738
|
+
return f4 === "none" || f4 === "transparent" || f4 === "rgba(0, 0, 0, 0)" || f4 === "rgba(0,0,0,0)";
|
|
1739
1739
|
}
|
|
1740
1740
|
function widthPx(raw) {
|
|
1741
1741
|
const m = /^(-?\d+(?:\.\d+)?)\s*(px)?$/i.exec(raw);
|
|
@@ -1789,6 +1789,195 @@ function hitBandFlag(c2) {
|
|
|
1789
1789
|
return c2.uncovered > 0 ? "hitband:d3:thin" : "hitband:d3:ok";
|
|
1790
1790
|
}
|
|
1791
1791
|
|
|
1792
|
+
// src/deltaE.ts
|
|
1793
|
+
function linearise(c2) {
|
|
1794
|
+
const v3 = c2 / 255;
|
|
1795
|
+
return v3 <= 0.04045 ? v3 / 12.92 : Math.pow((v3 + 0.055) / 1.055, 2.4);
|
|
1796
|
+
}
|
|
1797
|
+
var Xn = 0.95047;
|
|
1798
|
+
var Yn = 1;
|
|
1799
|
+
var Zn = 1.08883;
|
|
1800
|
+
var EPS = 216 / 24389;
|
|
1801
|
+
var KAPPA = 24389 / 27;
|
|
1802
|
+
function f2(t) {
|
|
1803
|
+
return t > EPS ? Math.cbrt(t) : (KAPPA * t + 16) / 116;
|
|
1804
|
+
}
|
|
1805
|
+
function rgbToLab(r, g3, b2) {
|
|
1806
|
+
const R = linearise(r), G3 = linearise(g3), B2 = linearise(b2);
|
|
1807
|
+
const X2 = 0.4124564 * R + 0.3575761 * G3 + 0.1804375 * B2;
|
|
1808
|
+
const Y2 = 0.2126729 * R + 0.7151522 * G3 + 0.072175 * B2;
|
|
1809
|
+
const Z3 = 0.0193339 * R + 0.119192 * G3 + 0.9503041 * B2;
|
|
1810
|
+
const fx = f2(X2 / Xn), fy = f2(Y2 / Yn), fz = f2(Z3 / Zn);
|
|
1811
|
+
return { L: 116 * fy - 16, a: 500 * (fx - fy), b: 200 * (fy - fz) };
|
|
1812
|
+
}
|
|
1813
|
+
function hexToLab(hex2) {
|
|
1814
|
+
const m = /^#?([0-9a-f]{3}|[0-9a-f]{6})$/i.exec(hex2.trim());
|
|
1815
|
+
if (!m) return null;
|
|
1816
|
+
const h2 = m[1].length === 3 ? m[1][0] + m[1][0] + m[1][1] + m[1][1] + m[1][2] + m[1][2] : m[1];
|
|
1817
|
+
return rgbToLab(parseInt(h2.slice(0, 2), 16), parseInt(h2.slice(2, 4), 16), parseInt(h2.slice(4, 6), 16));
|
|
1818
|
+
}
|
|
1819
|
+
var RAD = Math.PI / 180;
|
|
1820
|
+
var DEG = 180 / Math.PI;
|
|
1821
|
+
var NEUTRAL_CHROMA = 1e-4;
|
|
1822
|
+
function deltaE2000(c1, c2) {
|
|
1823
|
+
const C1 = Math.hypot(c1.a, c1.b), C2 = Math.hypot(c2.a, c2.b);
|
|
1824
|
+
const Cbar = (C1 + C2) / 2;
|
|
1825
|
+
const C7 = Math.pow(Cbar, 7);
|
|
1826
|
+
const G3 = 0.5 * (1 - Math.sqrt(C7 / (C7 + Math.pow(25, 7))));
|
|
1827
|
+
const a1p = (1 + G3) * c1.a, a2p = (1 + G3) * c2.a;
|
|
1828
|
+
const C1p = Math.hypot(a1p, c1.b), C2p = Math.hypot(a2p, c2.b);
|
|
1829
|
+
const neutral = C1p < NEUTRAL_CHROMA || C2p < NEUTRAL_CHROMA;
|
|
1830
|
+
const h1p = C1p < NEUTRAL_CHROMA ? 0 : (Math.atan2(c1.b, a1p) * DEG + 360) % 360;
|
|
1831
|
+
const h2p = C2p < NEUTRAL_CHROMA ? 0 : (Math.atan2(c2.b, a2p) * DEG + 360) % 360;
|
|
1832
|
+
const dLp = c2.L - c1.L;
|
|
1833
|
+
const dCp = C2p - C1p;
|
|
1834
|
+
let dhp;
|
|
1835
|
+
if (neutral) dhp = 0;
|
|
1836
|
+
else if (Math.abs(h2p - h1p) <= 180) dhp = h2p - h1p;
|
|
1837
|
+
else if (h2p - h1p > 180) dhp = h2p - h1p - 360;
|
|
1838
|
+
else dhp = h2p - h1p + 360;
|
|
1839
|
+
const dHp = 2 * Math.sqrt(C1p * C2p) * Math.sin(dhp / 2 * RAD);
|
|
1840
|
+
const Lbarp = (c1.L + c2.L) / 2;
|
|
1841
|
+
const Cbarp = (C1p + C2p) / 2;
|
|
1842
|
+
let hbarp;
|
|
1843
|
+
if (neutral) hbarp = h1p + h2p;
|
|
1844
|
+
else if (Math.abs(h1p - h2p) <= 180) hbarp = (h1p + h2p) / 2;
|
|
1845
|
+
else if (h1p + h2p < 360) hbarp = (h1p + h2p + 360) / 2;
|
|
1846
|
+
else hbarp = (h1p + h2p - 360) / 2;
|
|
1847
|
+
const T3 = 1 - 0.17 * Math.cos((hbarp - 30) * RAD) + 0.24 * Math.cos(2 * hbarp * RAD) + 0.32 * Math.cos((3 * hbarp + 6) * RAD) - 0.2 * Math.cos((4 * hbarp - 63) * RAD);
|
|
1848
|
+
const dTheta = 30 * Math.exp(-Math.pow((hbarp - 275) / 25, 2));
|
|
1849
|
+
const Cbarp7 = Math.pow(Cbarp, 7);
|
|
1850
|
+
const RC = 2 * Math.sqrt(Cbarp7 / (Cbarp7 + Math.pow(25, 7)));
|
|
1851
|
+
const RT = -RC * Math.sin(2 * dTheta * RAD);
|
|
1852
|
+
const Lm50 = Math.pow(Lbarp - 50, 2);
|
|
1853
|
+
const SL = 1 + 0.015 * Lm50 / Math.sqrt(20 + Lm50);
|
|
1854
|
+
const SC = 1 + 0.045 * Cbarp;
|
|
1855
|
+
const SH = 1 + 0.015 * Cbarp * T3;
|
|
1856
|
+
const tL = dLp / SL, tC = dCp / SC, tH = dHp / SH;
|
|
1857
|
+
return Math.sqrt(tL * tL + tC * tC + tH * tH + RT * tC * tH);
|
|
1858
|
+
}
|
|
1859
|
+
|
|
1860
|
+
// src/colourSpread.ts
|
|
1861
|
+
var SAME_SHADE_DELTA_E = 5;
|
|
1862
|
+
var MIN_RAMP_FILLS = 4;
|
|
1863
|
+
var RAMP_SLACK_MAX = 0.15;
|
|
1864
|
+
var MIN_MARKS = 24;
|
|
1865
|
+
var ELEMENT_CAP3 = 5e3;
|
|
1866
|
+
var MAX_CELLS = 48;
|
|
1867
|
+
var CELL_STEP = 32;
|
|
1868
|
+
var EMPTY3 = { marks: 0, distinctFills: 0, crowdShare: 0, spanDeltaE: 0 };
|
|
1869
|
+
function styleOf2(el, doc) {
|
|
1870
|
+
try {
|
|
1871
|
+
const view = doc?.defaultView;
|
|
1872
|
+
return view?.getComputedStyle ? view.getComputedStyle(el) : null;
|
|
1873
|
+
} catch {
|
|
1874
|
+
return null;
|
|
1875
|
+
}
|
|
1876
|
+
}
|
|
1877
|
+
function fillOf(el, cs) {
|
|
1878
|
+
const a4 = el.getAttribute?.("fill");
|
|
1879
|
+
if (a4 !== null && a4 !== void 0 && String(a4).trim() !== "") return String(a4).trim();
|
|
1880
|
+
const c2 = cs?.fill;
|
|
1881
|
+
return c2 === null || c2 === void 0 ? "" : String(c2).trim();
|
|
1882
|
+
}
|
|
1883
|
+
function toRgb(raw) {
|
|
1884
|
+
const s2 = raw.trim().toLowerCase();
|
|
1885
|
+
if (!s2 || s2 === "none" || s2 === "transparent") return null;
|
|
1886
|
+
const hex2 = /^#([0-9a-f]{3}|[0-9a-f]{6})$/.exec(s2);
|
|
1887
|
+
if (hex2) {
|
|
1888
|
+
const h2 = hex2[1];
|
|
1889
|
+
const full = h2.length === 3 ? h2[0] + h2[0] + h2[1] + h2[1] + h2[2] + h2[2] : h2;
|
|
1890
|
+
return [
|
|
1891
|
+
parseInt(full.slice(0, 2), 16),
|
|
1892
|
+
parseInt(full.slice(2, 4), 16),
|
|
1893
|
+
parseInt(full.slice(4, 6), 16)
|
|
1894
|
+
];
|
|
1895
|
+
}
|
|
1896
|
+
const m = /^rgba?\(\s*([\d.]+)[\s,]+([\d.]+)[\s,]+([\d.]+)\s*(?:[,/]\s*([\d.]+)\s*)?\)$/.exec(s2);
|
|
1897
|
+
if (!m) return null;
|
|
1898
|
+
if (m[4] !== void 0 && parseFloat(m[4]) === 0) return null;
|
|
1899
|
+
return [Math.round(parseFloat(m[1])), Math.round(parseFloat(m[2])), Math.round(parseFloat(m[3]))];
|
|
1900
|
+
}
|
|
1901
|
+
function cellKey(rgb) {
|
|
1902
|
+
return [
|
|
1903
|
+
Math.round(rgb[0] / CELL_STEP),
|
|
1904
|
+
Math.round(rgb[1] / CELL_STEP),
|
|
1905
|
+
Math.round(rgb[2] / CELL_STEP)
|
|
1906
|
+
].join(",");
|
|
1907
|
+
}
|
|
1908
|
+
function hex(rgb) {
|
|
1909
|
+
return "#" + rgb.map((v3) => Math.max(0, Math.min(255, v3)).toString(16).padStart(2, "0")).join("");
|
|
1910
|
+
}
|
|
1911
|
+
function censusColourSpread(container, doc) {
|
|
1912
|
+
if (!container || typeof container.querySelectorAll !== "function") return EMPTY3;
|
|
1913
|
+
try {
|
|
1914
|
+
const els = Array.from(
|
|
1915
|
+
container.querySelectorAll(`.${MARK_CLASS}, [${ROW_IDX_ATTR}]`)
|
|
1916
|
+
);
|
|
1917
|
+
if (els.length === 0 || els.length > ELEMENT_CAP3) return EMPTY3;
|
|
1918
|
+
const ownerDoc = doc ?? container.ownerDocument;
|
|
1919
|
+
const distinct = /* @__PURE__ */ new Set();
|
|
1920
|
+
const cells = /* @__PURE__ */ new Map();
|
|
1921
|
+
let marks = 0;
|
|
1922
|
+
for (const el of els) {
|
|
1923
|
+
const rgb = toRgb(fillOf(el, styleOf2(el, ownerDoc)));
|
|
1924
|
+
if (!rgb) continue;
|
|
1925
|
+
marks++;
|
|
1926
|
+
distinct.add(rgb.join(","));
|
|
1927
|
+
const k2 = cellKey(rgb);
|
|
1928
|
+
const cur = cells.get(k2);
|
|
1929
|
+
if (cur) cur.n++;
|
|
1930
|
+
else cells.set(k2, { rgb, n: 1 });
|
|
1931
|
+
}
|
|
1932
|
+
if (marks < MIN_MARKS || distinct.size < MIN_RAMP_FILLS) return EMPTY3;
|
|
1933
|
+
const top = [...cells.values()].sort((a4, b2) => b2.n - a4.n).slice(0, MAX_CELLS);
|
|
1934
|
+
const cs = top.map((c2) => hexToLab(hex(c2.rgb))).filter((l2) => l2 !== null);
|
|
1935
|
+
if (cs.length < MIN_RAMP_FILLS) return EMPTY3;
|
|
1936
|
+
const d = cs.map(() => new Array(cs.length).fill(0));
|
|
1937
|
+
let span = 0, lo = 0, hi = 1;
|
|
1938
|
+
for (let i2 = 0; i2 < cs.length; i2++) {
|
|
1939
|
+
for (let j3 = i2 + 1; j3 < cs.length; j3++) {
|
|
1940
|
+
const v3 = deltaE2000(cs[i2], cs[j3]);
|
|
1941
|
+
d[i2][j3] = v3;
|
|
1942
|
+
d[j3][i2] = v3;
|
|
1943
|
+
if (v3 > span) {
|
|
1944
|
+
span = v3;
|
|
1945
|
+
lo = i2;
|
|
1946
|
+
hi = j3;
|
|
1947
|
+
}
|
|
1948
|
+
}
|
|
1949
|
+
}
|
|
1950
|
+
if (span <= 0) return EMPTY3;
|
|
1951
|
+
let slack = 0, interior = 0;
|
|
1952
|
+
for (let i2 = 0; i2 < cs.length; i2++) {
|
|
1953
|
+
if (i2 === lo || i2 === hi) continue;
|
|
1954
|
+
slack += (d[lo][i2] + d[i2][hi]) / span - 1;
|
|
1955
|
+
interior++;
|
|
1956
|
+
}
|
|
1957
|
+
if (interior < 2 || slack / interior > RAMP_SLACK_MAX) return EMPTY3;
|
|
1958
|
+
let crowd = 0;
|
|
1959
|
+
for (let i2 = 0; i2 < cs.length; i2++) {
|
|
1960
|
+
let n = 0;
|
|
1961
|
+
for (let j3 = 0; j3 < cs.length; j3++) {
|
|
1962
|
+
if (i2 === j3 || d[i2][j3] <= SAME_SHADE_DELTA_E) n += top[j3].n;
|
|
1963
|
+
}
|
|
1964
|
+
if (n > crowd) crowd = n;
|
|
1965
|
+
}
|
|
1966
|
+
return {
|
|
1967
|
+
marks,
|
|
1968
|
+
distinctFills: distinct.size,
|
|
1969
|
+
crowdShare: Math.round(crowd / marks * 100),
|
|
1970
|
+
spanDeltaE: Math.round(span)
|
|
1971
|
+
};
|
|
1972
|
+
} catch {
|
|
1973
|
+
return EMPTY3;
|
|
1974
|
+
}
|
|
1975
|
+
}
|
|
1976
|
+
function colourSpreadFlag(c2) {
|
|
1977
|
+
if (c2.marks === 0) return "";
|
|
1978
|
+
return "ramp:d3:crowd" + Math.min(80, Math.floor(c2.crowdShare / 20) * 20);
|
|
1979
|
+
}
|
|
1980
|
+
|
|
1792
1981
|
// src/fit.ts
|
|
1793
1982
|
var SCROLL_SLACK_PX = 8;
|
|
1794
1983
|
function needsScroll(contentPx, viewportPx, slackPx = SCROLL_SLACK_PX) {
|
|
@@ -2403,15 +2592,15 @@ function clamp01(v3) {
|
|
|
2403
2592
|
if (typeof v3 !== "number" || !isFinite(v3)) return 1;
|
|
2404
2593
|
return Math.max(0, Math.min(1, v3));
|
|
2405
2594
|
}
|
|
2406
|
-
function hexToRGB(
|
|
2407
|
-
const p2 = toRGBA(
|
|
2595
|
+
function hexToRGB(hex2) {
|
|
2596
|
+
const p2 = toRGBA(hex2);
|
|
2408
2597
|
return [p2[0], p2[1], p2[2]];
|
|
2409
2598
|
}
|
|
2410
2599
|
|
|
2411
2600
|
// src/labelContrastDom.ts
|
|
2412
2601
|
var LABEL_CONTRAST_DONE_ATTR = "data-lch-contrast";
|
|
2413
2602
|
var LABEL_CONTRAST_CAP = 2e3;
|
|
2414
|
-
var
|
|
2603
|
+
var EMPTY4 = { rects: 0, scanned: 0, fixed: 0, pillsBoosted: 0, offFill: 0, pageMajority: 0 };
|
|
2415
2604
|
function backedSamples(el, pts) {
|
|
2416
2605
|
try {
|
|
2417
2606
|
const ge2 = el;
|
|
@@ -2434,7 +2623,7 @@ function backedSamples(el, pts) {
|
|
|
2434
2623
|
}
|
|
2435
2624
|
}
|
|
2436
2625
|
function applyLabelContrast(container, opts = {}) {
|
|
2437
|
-
const report = { ...
|
|
2626
|
+
const report = { ...EMPTY4 };
|
|
2438
2627
|
if (!container) {
|
|
2439
2628
|
report.skipped = "no-container";
|
|
2440
2629
|
return report;
|
|
@@ -2897,6 +3086,12 @@ function createChartHost(container, config) {
|
|
|
2897
3086
|
} catch {
|
|
2898
3087
|
}
|
|
2899
3088
|
}
|
|
3089
|
+
if (config.onColourSpreadCensus) {
|
|
3090
|
+
try {
|
|
3091
|
+
config.onColourSpreadCensus(censusColourSpread(container, doc));
|
|
3092
|
+
} catch {
|
|
3093
|
+
}
|
|
3094
|
+
}
|
|
2900
3095
|
if (fitOpts !== false) {
|
|
2901
3096
|
try {
|
|
2902
3097
|
const r = fitRenderedChart(container, fitOpts === true ? {} : fitOpts);
|
|
@@ -3016,6 +3211,10 @@ export {
|
|
|
3016
3211
|
MIN_HIT_BAND_PX,
|
|
3017
3212
|
censusHitBands,
|
|
3018
3213
|
hitBandFlag,
|
|
3214
|
+
SAME_SHADE_DELTA_E,
|
|
3215
|
+
MIN_RAMP_FILLS,
|
|
3216
|
+
censusColourSpread,
|
|
3217
|
+
colourSpreadFlag,
|
|
3019
3218
|
SCROLL_SLACK_PX,
|
|
3020
3219
|
needsScroll,
|
|
3021
3220
|
contentExtentOf,
|
package/dist/index.mjs
CHANGED
|
@@ -44,6 +44,7 @@ import {
|
|
|
44
44
|
MAX_FRAME_GROW_FACTOR,
|
|
45
45
|
MIN_CONTRAST,
|
|
46
46
|
MIN_HIT_BAND_PX,
|
|
47
|
+
MIN_RAMP_FILLS,
|
|
47
48
|
Me,
|
|
48
49
|
PAGE_MATCH_TOLERANCE,
|
|
49
50
|
PHANTOM_FRACTION,
|
|
@@ -51,6 +52,7 @@ import {
|
|
|
51
52
|
PILL_MIN_COVERAGE,
|
|
52
53
|
PILL_OPAQUE_ALPHA,
|
|
53
54
|
ROW_IDX_ATTR,
|
|
55
|
+
SAME_SHADE_DELTA_E,
|
|
54
56
|
SCROLL_SLACK_PX,
|
|
55
57
|
SEASONAL_MARKERS_DEFAULT,
|
|
56
58
|
SELECTION_ACTIVE_CLASS,
|
|
@@ -64,10 +66,12 @@ import {
|
|
|
64
66
|
blankRenderFlag,
|
|
65
67
|
buildRenderPayload,
|
|
66
68
|
cellSuppressesNormalize,
|
|
69
|
+
censusColourSpread,
|
|
67
70
|
censusHitBands,
|
|
68
71
|
censusMarks,
|
|
69
72
|
chartOwnsTimeline,
|
|
70
73
|
clearGeoCache,
|
|
74
|
+
colourSpreadFlag,
|
|
71
75
|
compileRenderFn,
|
|
72
76
|
compositeOver,
|
|
73
77
|
contentExtentOf,
|
|
@@ -112,7 +116,7 @@ import {
|
|
|
112
116
|
u,
|
|
113
117
|
unpinScrolledAxis,
|
|
114
118
|
vt
|
|
115
|
-
} from "./chunk-
|
|
119
|
+
} from "./chunk-YIRWZUKN.mjs";
|
|
116
120
|
import "./chunk-A2GMXZP7.mjs";
|
|
117
121
|
import "./chunk-GHODWOAL.mjs";
|
|
118
122
|
|
|
@@ -2083,6 +2087,7 @@ export {
|
|
|
2083
2087
|
MIN_CONTRAST,
|
|
2084
2088
|
MIN_DELTA_E,
|
|
2085
2089
|
MIN_HIT_BAND_PX,
|
|
2090
|
+
MIN_RAMP_FILLS,
|
|
2086
2091
|
PAGE_MATCH_TOLERANCE,
|
|
2087
2092
|
PHANTOM_FRACTION,
|
|
2088
2093
|
PILL_MIN_ALPHA,
|
|
@@ -2090,6 +2095,7 @@ export {
|
|
|
2090
2095
|
PILL_OPAQUE_ALPHA,
|
|
2091
2096
|
QUALIFY_REFUSAL_UNSPECIFIED,
|
|
2092
2097
|
ROW_IDX_ATTR,
|
|
2098
|
+
SAME_SHADE_DELTA_E,
|
|
2093
2099
|
SCROLL_SLACK_PX,
|
|
2094
2100
|
SEASONAL_MARKERS_DEFAULT,
|
|
2095
2101
|
SELECTION_ACTIVE_CLASS,
|
|
@@ -2110,11 +2116,13 @@ export {
|
|
|
2110
2116
|
canConfirmLaunch,
|
|
2111
2117
|
captureSvgSnapshot,
|
|
2112
2118
|
cellSuppressesNormalize,
|
|
2119
|
+
censusColourSpread,
|
|
2113
2120
|
censusHitBands,
|
|
2114
2121
|
censusMarks,
|
|
2115
2122
|
chartOwnsTimeline,
|
|
2116
2123
|
chooserFitsViewport,
|
|
2117
2124
|
clearGeoCache,
|
|
2125
|
+
colourSpreadFlag,
|
|
2118
2126
|
compileRenderFn,
|
|
2119
2127
|
compileTrivialSource,
|
|
2120
2128
|
compositeOver,
|
package/dist/react.mjs
CHANGED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CIE2000 distance at which two fills stop being separable at a glance, side by side on a chart.
|
|
3
|
+
*
|
|
4
|
+
* Not a tuned parameter — a perceptual constant. 1.0 is the textbook just-noticeable difference
|
|
5
|
+
* under laboratory conditions with the two patches touching; 5 is the conventional "clearly
|
|
6
|
+
* different to an ordinary observer in ordinary conditions", which is what a reader scanning a
|
|
7
|
+
* choropleth is. Erring high is the safe direction: it makes the census UNDERstate crowding.
|
|
8
|
+
*/
|
|
9
|
+
export declare const SAME_SHADE_DELTA_E = 5;
|
|
10
|
+
/**
|
|
11
|
+
* Fewer distinct fills than this and there is nothing to characterise.
|
|
12
|
+
*
|
|
13
|
+
* Four is the floor for the collinearity test below, not a judgement: the two extremes anchor the
|
|
14
|
+
* line, so a fourth fill is the second interior point and the first one that can disagree.
|
|
15
|
+
*/
|
|
16
|
+
export declare const MIN_RAMP_FILLS = 4;
|
|
17
|
+
/**
|
|
18
|
+
* How far off a straight line a set of fills may sit and still be a RAMP.
|
|
19
|
+
*
|
|
20
|
+
* THIS IS WHAT SEPARATES A VALUE-ENCODED COLOUR CHANNEL FROM A CATEGORICAL ONE, and counting
|
|
21
|
+
* fills cannot do it. The obvious "at least six distinct colours" rule fails at exactly the
|
|
22
|
+
* wrong moment: a five-bin quantile scale — the recommended REMEDY for the washout this census
|
|
23
|
+
* exists to find — has five fills, so a count floor would have excluded the charts that did the
|
|
24
|
+
* right thing and biased the prevalence it was built to measure.
|
|
25
|
+
*
|
|
26
|
+
* A sequential ramp is, by construction, a path between two colours: every fill lies close to the
|
|
27
|
+
* segment joining its extremes, so `d(lo,x) + d(x,hi)` barely exceeds `d(lo,hi)`. A categorical
|
|
28
|
+
* scheme is chosen for mutual separation and its members sit well off that line. Measured in
|
|
29
|
+
* CIE2000 over the standard schemes, the two populations do not overlap:
|
|
30
|
+
*
|
|
31
|
+
* ```text
|
|
32
|
+
* interpolateBlues (5, 8 and 40 stops) mean slack -0.05 SEQUENTIAL
|
|
33
|
+
* interpolateReds (8) mean slack +0.06 SEQUENTIAL
|
|
34
|
+
* viridis (8) mean slack +0.02 SEQUENTIAL
|
|
35
|
+
* schemeTableau10 (5 and 8) mean slack +0.24 categorical
|
|
36
|
+
* RdBu diverging (7) mean slack +0.35 two arms, not one line
|
|
37
|
+
* ```
|
|
38
|
+
*
|
|
39
|
+
* 0.15 sits in the four-fold gap. A DIVERGING ramp landing outside is correct rather than a miss:
|
|
40
|
+
* it is genuinely two paths from a neutral middle, and measuring it as one would report the arm
|
|
41
|
+
* that happened to be longer. It is excluded and said so, not mismeasured.
|
|
42
|
+
*/
|
|
43
|
+
export declare const RAMP_SLACK_MAX = 0.15;
|
|
44
|
+
export interface ColourSpreadCensus {
|
|
45
|
+
/** Marks carrying a resolvable, non-transparent fill. */
|
|
46
|
+
marks: number;
|
|
47
|
+
/** Distinct fills among them, before quantisation. */
|
|
48
|
+
distinctFills: number;
|
|
49
|
+
/** Share (0-100) of marks whose fill is within SAME_SHADE_DELTA_E of the most crowded fill. */
|
|
50
|
+
crowdShare: number;
|
|
51
|
+
/** Largest CIE2000 distance between any two sampled fills — the ramp's perceptual reach. */
|
|
52
|
+
spanDeltaE: number;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* How much of this chart is one shade?
|
|
56
|
+
*
|
|
57
|
+
* Never throws. Telemetry must not be the reason a delivered render fails, and an environment
|
|
58
|
+
* that cannot report a fill reports nothing rather than a number that describes the environment.
|
|
59
|
+
*
|
|
60
|
+
* KNOWN LIMIT, stated rather than hidden: a DIVERGING ramp is measured the same way as any
|
|
61
|
+
* other, so a chart whose two arms are each well spread but which crowds around its neutral
|
|
62
|
+
* midpoint reports honestly, while one that crowds at BOTH ends reports the larger arm only. That
|
|
63
|
+
* understates rather than overstates, which is the direction an audit should err.
|
|
64
|
+
*/
|
|
65
|
+
export declare function censusColourSpread(container: any, doc?: any): ColourSpreadCensus;
|
|
66
|
+
/**
|
|
67
|
+
* The always-on behaviour tag, or "" when the census had nothing to say.
|
|
68
|
+
*
|
|
69
|
+
* A BUCKETED MEASUREMENT, NOT A VERDICT. `ramp:d3:crowd60` says three in five marks are one
|
|
70
|
+
* shade; it does not say that is wrong. Twenty-point buckets are coarse enough to read as a
|
|
71
|
+
* distribution off a few hundred renders and fine enough to separate "a bit clustered" from the
|
|
72
|
+
* failure this exists for, and the whole family is one `LIKE 'ramp:d3:crowd%'` away — which is
|
|
73
|
+
* the denominator any rate needs. When the distribution is in, a cut can be argued from it.
|
|
74
|
+
*/
|
|
75
|
+
export declare function colourSpreadFlag(c: ColourSpreadCensus): string;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/** CIE L*a*b*, D65. */
|
|
2
|
+
export interface Lab {
|
|
3
|
+
L: number;
|
|
4
|
+
a: number;
|
|
5
|
+
b: number;
|
|
6
|
+
}
|
|
7
|
+
/** sRGB (0-255 per channel) to CIE L*a*b*. */
|
|
8
|
+
export declare function rgbToLab(r: number, g: number, b: number): Lab;
|
|
9
|
+
/** `#rgb` / `#rrggbb` to Lab. Returns null on anything else rather than guessing. */
|
|
10
|
+
export declare function hexToLab(hex: string): Lab | null;
|
|
11
|
+
/**
|
|
12
|
+
* CIEDE2000, with the standard parametric weights (kL = kC = kH = 1).
|
|
13
|
+
*
|
|
14
|
+
* Transcribed from the published formulation rather than from another implementation - which is
|
|
15
|
+
* why it does not match colorsea, and why deltaE.test.ts proves that is colorsea's doing rather
|
|
16
|
+
* than a slip here. The two fiddly parts, which is where transcriptions usually go
|
|
17
|
+
* wrong: the mean hue h-bar must account for the 360-degree wrap (and is undefined, so taken as
|
|
18
|
+
* the sum, when either chroma is zero), and the rotation term applies only in the blue region -
|
|
19
|
+
* without it, two blues read as further apart than they look, which is exactly the region a
|
|
20
|
+
* sequential ramp spends most of its length in.
|
|
21
|
+
*/
|
|
22
|
+
export declare function deltaE2000(c1: Lab, c2: Lab): number;
|
|
23
|
+
/** CIEDE2000 between two `#rrggbb` colours. NaN when either cannot be parsed. */
|
|
24
|
+
export declare function deltaEHex(a: string, b: string): number;
|
package/dist/types/host.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ import { type RenderOptions, type ViewStateProvider } from "./contract";
|
|
|
2
2
|
import { type ResolveOptionsInput } from "./defaults";
|
|
3
3
|
import { type MarkCensus } from "./blankRender";
|
|
4
4
|
import { type HitBandCensus } from "./hitBands";
|
|
5
|
+
import { type ColourSpreadCensus } from "./colourSpread";
|
|
5
6
|
import { type FitRenderedChartOptions, type FitRenderedChartResult } from "./fitDom";
|
|
6
7
|
import { type LabelContrastOptions, type LabelContrastReport } from "./labelContrastDom";
|
|
7
8
|
export type RenderFn = (container: HTMLElement, data: any, options: RenderOptions) => void;
|
|
@@ -92,6 +93,21 @@ export interface ChartHostConfig {
|
|
|
92
93
|
* number only the browser knows, and this reads the COMPUTED width off the rendered element.
|
|
93
94
|
*/
|
|
94
95
|
onHitBandCensus?: (census: HitBandCensus) => void;
|
|
96
|
+
/**
|
|
97
|
+
* HOW MUCH OF THIS CHART IS ONE SHADE (2026-09-09)? Runs after every render, counts only.
|
|
98
|
+
*
|
|
99
|
+
* The sibling question to the hit-band census, on the colour channel: a right-skewed measure
|
|
100
|
+
* on a linear ramp is accurate and unreadable, because the outliers eat the ramp and the
|
|
101
|
+
* dense bulk lands in one indistinguishable tint. It measures the OUTCOME, never the scale,
|
|
102
|
+
* so a well-spread scale of any kind reports well and a curved or hand-rolled ramp needs no
|
|
103
|
+
* special case; it declines outright on a categorical palette or a diverging ramp, which are
|
|
104
|
+
* a different question wearing the same numbers.
|
|
105
|
+
*
|
|
106
|
+
* The other half a server-side check cannot do. A code rule reads `scaleLinear()` and a
|
|
107
|
+
* domain built from `d3.max`; whether THAT washes out depends on the data, and the shape's
|
|
108
|
+
* own skew is measured on the raw column while the ramp encodes an aggregate.
|
|
109
|
+
*/
|
|
110
|
+
onColourSpreadCensus?: (census: ColourSpreadCensus) => void;
|
|
95
111
|
/** This chart declares time keyframes: frame one is allowed to be empty, so no blank verdict
|
|
96
112
|
* is issued for it. */
|
|
97
113
|
animated?: boolean;
|
package/dist/types/index.d.ts
CHANGED
|
@@ -21,6 +21,7 @@ export { applyLabelContrast, LABEL_CONTRAST_DONE_ATTR, LABEL_CONTRAST_CAP, type
|
|
|
21
21
|
export { decideLabelColor, toRGBA, compositeOver, relativeLuminance, contrastRatio, isPillBackdropAlpha, pillBacksGlyph, backingHoldsGlyph, cellSuppressesNormalize, glyphSampleGrid, DARK_TEXT, LIGHT_TEXT, MIN_CONTRAST, WHITE_TEXT_BG_LUM, PILL_MIN_ALPHA, PILL_OPAQUE_ALPHA, PILL_MIN_COVERAGE, PAGE_MATCH_TOLERANCE, BACKING_MAJORITY, GLYPH_SAMPLE_N, type LabelDecision, } from "./labelContrast";
|
|
22
22
|
export { censusMarks, isBlankRender, blankRenderFlag, type MarkCensus, type BlankVerdictInput } from "./blankRender";
|
|
23
23
|
export { censusHitBands, hitBandFlag, MIN_HIT_BAND_PX, type HitBandCensus } from "./hitBands";
|
|
24
|
+
export { censusColourSpread, colourSpreadFlag, SAME_SHADE_DELTA_E, MIN_RAMP_FILLS, type ColourSpreadCensus } from "./colourSpread";
|
|
24
25
|
export { SCROLL_SLACK_PX, MAX_FRAME_GROW_FACTOR, PHANTOM_FRACTION, FIT_CONTENT_SELECTOR, needsScroll, contentExtentOf, scrollFitFor, planFrameGrow, isPhantomBox, type MeasuredBox, type ContentExtent, type ScrollFit, type FrameGrowPlan, } from "./fit";
|
|
25
26
|
export { fitRenderedChart, fitReadingFor, measureContainerBoxes, svgInkReach, ctmScaleOf, type FitReading, type InkReach, type FitRenderedChartOptions, type FitRenderedChartResult, } from "./fitDom";
|
|
26
27
|
export { AXIS_PIN_MIN_LABELS, AXIS_PIN_BAND_PAD_PX, AXIS_PIN_MAX_BAND_FRACTION, AXIS_PIN_TRACK_REACH_PX, isHorizontalLabelRow, labelBand, planAxisPin, axisPinPlacement, type LabelRowBox, type AxisBand, type AxisPinCandidate, type AxisPinPlan, type AxisPinEdge, } from "./fit";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bicharts/chart-host",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.91",
|
|
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",
|