@bicharts/chart-host 0.6.99 → 0.6.103
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/adapters.mjs +3 -3
- package/dist/card.mjs +2 -2
- package/dist/{chunk-RAKU2JBE.mjs → chunk-4BR6VJQX.mjs} +753 -44
- package/dist/{chunk-M7MBTLDP.mjs → chunk-7XRQUFVH.mjs} +3 -1
- package/dist/{chunk-W5L6OH25.mjs → chunk-CNT3QA3R.mjs} +1 -1
- package/dist/{chunk-ASLRGGLV.mjs → chunk-CPLWAW3Z.mjs} +1 -1
- package/dist/{chunk-LDMLLLC6.mjs → chunk-D6A37G2G.mjs} +1 -1
- package/dist/{chunk-B6BLSIID.mjs → chunk-IE426WU6.mjs} +2 -2
- package/dist/{chunk-3JBJ2SIF.mjs → chunk-IE7TM6DX.mjs} +1 -1
- package/dist/{chunk-5OCL4EFM.mjs → chunk-P2DLK7WZ.mjs} +1 -1
- package/dist/{chunk-PMA56BKD.mjs → chunk-PA5V6J6K.mjs} +1 -1
- package/dist/{chunk-WSNDXS3Z.mjs → chunk-TLIBO5PT.mjs} +1 -1
- package/dist/index.mjs +192 -9
- package/dist/legend-fit.mjs +3 -3
- package/dist/page.mjs +4 -4
- package/dist/react.mjs +8 -8
- package/dist/testing.mjs +1 -1
- package/dist/types/contract.d.ts +8 -1
- package/dist/types/exportTable.d.ts +100 -0
- package/dist/types/host.d.ts +3 -2
- package/dist/types/hostLinks.d.ts +11 -0
- package/dist/types/index.d.ts +4 -1
- package/dist/types/shareRate.d.ts +90 -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-IE426WU6.mjs";
|
|
8
8
|
import {
|
|
9
9
|
censusHitBands,
|
|
10
10
|
ensureCrossfilterHitTargets
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-CPLWAW3Z.mjs";
|
|
12
12
|
import {
|
|
13
13
|
clearPress,
|
|
14
14
|
clearSelectionGlyphs,
|
|
@@ -25,14 +25,14 @@ import {
|
|
|
25
25
|
selectionRuleOf,
|
|
26
26
|
trackPress,
|
|
27
27
|
validRowSet
|
|
28
|
-
} from "./chunk-
|
|
28
|
+
} from "./chunk-P2DLK7WZ.mjs";
|
|
29
29
|
import {
|
|
30
30
|
clipWindowOf,
|
|
31
31
|
fitRenderedChart,
|
|
32
32
|
rememberScroll,
|
|
33
33
|
takeScroll,
|
|
34
34
|
unpinScrolledAxis
|
|
35
|
-
} from "./chunk-
|
|
35
|
+
} from "./chunk-IE7TM6DX.mjs";
|
|
36
36
|
import {
|
|
37
37
|
Fn,
|
|
38
38
|
J3,
|
|
@@ -40,7 +40,7 @@ import {
|
|
|
40
40
|
Yn,
|
|
41
41
|
ir,
|
|
42
42
|
tt
|
|
43
|
-
} from "./chunk-
|
|
43
|
+
} from "./chunk-CNT3QA3R.mjs";
|
|
44
44
|
import {
|
|
45
45
|
NA_ISO3,
|
|
46
46
|
NA_LAT_MAX,
|
|
@@ -79,6 +79,7 @@ import {
|
|
|
79
79
|
MARK_CLASS,
|
|
80
80
|
MARK_SELECTED_CLASS,
|
|
81
81
|
MAX_MAP_POINTS_DEFAULT,
|
|
82
|
+
NOTE_STYLE_ATTR,
|
|
82
83
|
NO_ROW_MARKS_ATTR,
|
|
83
84
|
ROW_IDX_ATTR,
|
|
84
85
|
SEASONAL_MARKERS_DEFAULT,
|
|
@@ -87,7 +88,7 @@ import {
|
|
|
87
88
|
XFILTER_REFRESH_EVENT,
|
|
88
89
|
chartOwnsTimeline,
|
|
89
90
|
periodTickSuppressesFeedback
|
|
90
|
-
} from "./chunk-
|
|
91
|
+
} from "./chunk-7XRQUFVH.mjs";
|
|
91
92
|
|
|
92
93
|
// src/labelContrast.ts
|
|
93
94
|
function parseRGBA(c) {
|
|
@@ -553,7 +554,505 @@ function resolveAutoColorScale(p) {
|
|
|
553
554
|
return memoValue;
|
|
554
555
|
}
|
|
555
556
|
|
|
557
|
+
// src/exportTable.ts
|
|
558
|
+
var EXPORT_FORMATS = Object.freeze(["xlsx", "csv"]);
|
|
559
|
+
var XLSX_MIME = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
|
|
560
|
+
var CSV_MIME = "text/csv";
|
|
561
|
+
var XLSX_MAX_ROWS = 1048576;
|
|
562
|
+
var XLSX_MAX_COLS = 16384;
|
|
563
|
+
var XLSX_MAX_CELL_CHARS = 32767;
|
|
564
|
+
function isBlank(v) {
|
|
565
|
+
return v === null || v === void 0 || typeof v === "string" && v.trim() === "";
|
|
566
|
+
}
|
|
567
|
+
function asNumber(v) {
|
|
568
|
+
if (isBlank(v) || typeof v === "boolean") return null;
|
|
569
|
+
if (v instanceof Date) return null;
|
|
570
|
+
const n = typeof v === "number" ? v : Number(String(v).trim());
|
|
571
|
+
return Number.isFinite(n) ? n : null;
|
|
572
|
+
}
|
|
573
|
+
function asTime(v) {
|
|
574
|
+
if (isBlank(v) || typeof v === "boolean") return null;
|
|
575
|
+
if (v instanceof Date) {
|
|
576
|
+
const t2 = v.getTime();
|
|
577
|
+
return Number.isFinite(t2) ? t2 : null;
|
|
578
|
+
}
|
|
579
|
+
if (typeof v === "number") return Number.isFinite(v) ? v : null;
|
|
580
|
+
const s = String(v).trim();
|
|
581
|
+
const day = /^(\d{4})-(\d{2})-(\d{2})$/.exec(s);
|
|
582
|
+
if (day) return Date.UTC(+day[1], +day[2] - 1, +day[3]);
|
|
583
|
+
const t = Date.parse(s);
|
|
584
|
+
return Number.isFinite(t) ? t : null;
|
|
585
|
+
}
|
|
586
|
+
function asBoolean(v) {
|
|
587
|
+
if (v === true || v === false) return v;
|
|
588
|
+
if (isBlank(v)) return null;
|
|
589
|
+
const s = String(v).trim().toLowerCase();
|
|
590
|
+
if (s === "true" || s === "1" || s === "yes") return true;
|
|
591
|
+
if (s === "false" || s === "0" || s === "no") return false;
|
|
592
|
+
return null;
|
|
593
|
+
}
|
|
594
|
+
function asText(v) {
|
|
595
|
+
if (v === null || v === void 0) return "";
|
|
596
|
+
if (v instanceof Date) return Number.isFinite(v.getTime()) ? v.toISOString() : "";
|
|
597
|
+
return String(v);
|
|
598
|
+
}
|
|
599
|
+
var DAY_MS = 864e5;
|
|
600
|
+
function hasTimeOfDay(t) {
|
|
601
|
+
return (t % DAY_MS + DAY_MS) % DAY_MS !== 0;
|
|
602
|
+
}
|
|
603
|
+
function pad2(n) {
|
|
604
|
+
return n < 10 ? "0" + n : String(n);
|
|
605
|
+
}
|
|
606
|
+
function isoDay(t) {
|
|
607
|
+
const d = new Date(t);
|
|
608
|
+
return d.getUTCFullYear() + "-" + pad2(d.getUTCMonth() + 1) + "-" + pad2(d.getUTCDate());
|
|
609
|
+
}
|
|
610
|
+
function isoDayTime(t) {
|
|
611
|
+
const d = new Date(t);
|
|
612
|
+
return isoDay(t) + " " + pad2(d.getUTCHours()) + ":" + pad2(d.getUTCMinutes()) + ":" + pad2(d.getUTCSeconds());
|
|
613
|
+
}
|
|
614
|
+
function excelSerial(t) {
|
|
615
|
+
const s = t / DAY_MS + 25569;
|
|
616
|
+
return s < 61 ? s - 1 : s;
|
|
617
|
+
}
|
|
618
|
+
var EXCEL_FIRST_DAY = Date.UTC(1900, 0, 1);
|
|
619
|
+
function fractionDigits(n) {
|
|
620
|
+
const s = String(Math.abs(n));
|
|
621
|
+
if (/e/i.test(s)) return 0;
|
|
622
|
+
const dot = s.indexOf(".");
|
|
623
|
+
return dot < 0 ? 0 : Math.min(15, s.length - dot - 1);
|
|
624
|
+
}
|
|
625
|
+
var D3_SPEC_RE = /^(?:(.)?([<>=^]))?([+\-( ])?([$#])?(0)?(\d+)?(,)?(\.\d+)?(~)?([a-z%])?$/i;
|
|
626
|
+
function shapeFromD3(spec) {
|
|
627
|
+
const m = D3_SPEC_RE.exec(spec.trim());
|
|
628
|
+
if (!m) return null;
|
|
629
|
+
const sign = m[3] || "", symbol = m[4] || "", group = !!m[7], trim = !!m[9], type = m[10] || "";
|
|
630
|
+
const p = m[8] ? parseInt(m[8].slice(1), 10) : null;
|
|
631
|
+
const base = { prefix: symbol === "$" ? "$" : "", suffix: "", group, minD: 0, maxD: 0, percent: false, plus: sign === "+", parens: sign === "(", scientific: false };
|
|
632
|
+
if (type === "f") {
|
|
633
|
+
const d = p === null ? 6 : p;
|
|
634
|
+
return { ...base, maxD: d, minD: trim ? 0 : d };
|
|
635
|
+
}
|
|
636
|
+
if (type === "%") {
|
|
637
|
+
const d = p === null ? 6 : p;
|
|
638
|
+
return { ...base, percent: true, maxD: d, minD: trim ? 0 : d };
|
|
639
|
+
}
|
|
640
|
+
if (type === "d") return base;
|
|
641
|
+
if (type === "e") {
|
|
642
|
+
const d = p === null ? 6 : p;
|
|
643
|
+
return { ...base, scientific: true, maxD: d, minD: d };
|
|
644
|
+
}
|
|
645
|
+
if ((type === "" || type === "n" || type === "g" || type === "r") && (group || type === "n")) return { ...base, group: true, maxD: 15, minD: 0 };
|
|
646
|
+
return null;
|
|
647
|
+
}
|
|
648
|
+
function shapeFromModel(fmt) {
|
|
649
|
+
const sections = fmt.split(";");
|
|
650
|
+
const sec = sections[0];
|
|
651
|
+
const bracketSym = (/\[\$([^\-\]]+)/.exec(sec) || [])[1] || "";
|
|
652
|
+
const noTok = sec.replace(/\[[^\]]*\]/g, "");
|
|
653
|
+
const bare = noTok.replace(/"[^"]*"/g, "").replace(/\\./g, "");
|
|
654
|
+
const pct = bare.indexOf("%") >= 0;
|
|
655
|
+
if (!pct && !/[0#]/.test(bare)) return null;
|
|
656
|
+
let sym = bracketSym;
|
|
657
|
+
let symAfter = false;
|
|
658
|
+
if (!sym) {
|
|
659
|
+
const lit = /"([^"]*[$\u20AC\u00A3\u00A5][^"]*)"/.exec(noTok);
|
|
660
|
+
const cur = lit ? null : /\\?([$\u20AC\u00A3\u00A5])/.exec(noTok);
|
|
661
|
+
if (lit) sym = lit[1].trim();
|
|
662
|
+
else if (cur) sym = cur[1];
|
|
663
|
+
}
|
|
664
|
+
if (sym) {
|
|
665
|
+
const firstDigit = noTok.search(/[0#]/);
|
|
666
|
+
const at = noTok.indexOf(sym);
|
|
667
|
+
symAfter = at >= 0 && firstDigit >= 0 && at > firstDigit;
|
|
668
|
+
}
|
|
669
|
+
const dm = /\.([0#]+)/.exec(bare);
|
|
670
|
+
const maxD = dm ? dm[1].length : 0, minD = dm ? dm[1].replace(/#/g, "").length : 0;
|
|
671
|
+
return {
|
|
672
|
+
prefix: sym && !symAfter ? sym : "",
|
|
673
|
+
suffix: sym && symAfter ? sym : "",
|
|
674
|
+
group: bare.indexOf(",") >= 0,
|
|
675
|
+
minD,
|
|
676
|
+
maxD: Math.min(15, maxD),
|
|
677
|
+
percent: pct,
|
|
678
|
+
plus: /^\s*\+/.test(bare),
|
|
679
|
+
parens: sections.length > 1 && /\(/.test(sections[1]) && /\)/.test(sections[1]),
|
|
680
|
+
scientific: false
|
|
681
|
+
};
|
|
682
|
+
}
|
|
683
|
+
function quoteLiteral(s) {
|
|
684
|
+
return s ? '"' + s.replace(/"/g, "") + '"' : "";
|
|
685
|
+
}
|
|
686
|
+
function codeFromShape(sh, dataFrac) {
|
|
687
|
+
const d = Math.max(sh.minD, Math.min(sh.maxD, dataFrac));
|
|
688
|
+
if (sh.scientific) return "0" + (d > 0 ? "." + "0".repeat(d) : "") + "E+00";
|
|
689
|
+
const core = (sh.group ? "#,##0" : "0") + (d > 0 ? "." + "0".repeat(d) : "") + (sh.percent ? "%" : "");
|
|
690
|
+
const body = quoteLiteral(sh.prefix) + core + quoteLiteral(sh.suffix);
|
|
691
|
+
if (!sh.plus && !sh.parens) {
|
|
692
|
+
return body === "0" ? null : body;
|
|
693
|
+
}
|
|
694
|
+
const pos = (sh.plus ? "+" : "") + body;
|
|
695
|
+
const neg = sh.parens ? "(" + body + ")" : "-" + body;
|
|
696
|
+
return pos + ";" + neg + ";" + body;
|
|
697
|
+
}
|
|
698
|
+
function excelNumberFormat(col, values = []) {
|
|
699
|
+
let sh = null;
|
|
700
|
+
if (typeof col.d3Format === "string" && col.d3Format.trim()) sh = shapeFromD3(col.d3Format);
|
|
701
|
+
else if (typeof col.modelFormat === "string" && col.modelFormat.trim()) sh = shapeFromModel(col.modelFormat);
|
|
702
|
+
if (!sh) return null;
|
|
703
|
+
let frac = 0;
|
|
704
|
+
for (const v of values) {
|
|
705
|
+
const f2 = fractionDigits(sh.percent ? Math.round(v * 100 * 1e9) / 1e9 : v);
|
|
706
|
+
if (f2 > frac) frac = f2;
|
|
707
|
+
}
|
|
708
|
+
return codeFromShape(sh, frac);
|
|
709
|
+
}
|
|
710
|
+
var FORMULA_START_RE = /^[=+\-@\t\r]/;
|
|
711
|
+
function csvField(s) {
|
|
712
|
+
return /[",\r\n]/.test(s) ? '"' + s.replace(/"/g, '""') + '"' : s;
|
|
713
|
+
}
|
|
714
|
+
function columnUsesTime(table, ci) {
|
|
715
|
+
for (const r of table.rows) {
|
|
716
|
+
const t = asTime(r[ci]);
|
|
717
|
+
if (t !== null && hasTimeOfDay(t)) return true;
|
|
718
|
+
}
|
|
719
|
+
return false;
|
|
720
|
+
}
|
|
721
|
+
function tableToCsv(table) {
|
|
722
|
+
const cols = table.columns;
|
|
723
|
+
const withTime = cols.map((c, ci) => c.type === "date" && columnUsesTime(table, ci));
|
|
724
|
+
const lines = [cols.map((c) => csvField(guardText(c.name))).join(",")];
|
|
725
|
+
for (const row of table.rows) {
|
|
726
|
+
const out = [];
|
|
727
|
+
for (let ci = 0; ci < cols.length; ci++) {
|
|
728
|
+
const c = cols[ci], v = row[ci];
|
|
729
|
+
if (c.type === "number") {
|
|
730
|
+
const n = asNumber(v);
|
|
731
|
+
out.push(n === null ? "" : String(n));
|
|
732
|
+
continue;
|
|
733
|
+
}
|
|
734
|
+
if (c.type === "date") {
|
|
735
|
+
const t = asTime(v);
|
|
736
|
+
out.push(t === null ? csvField(guardText(asText(v))) : withTime[ci] ? isoDayTime(t) : isoDay(t));
|
|
737
|
+
continue;
|
|
738
|
+
}
|
|
739
|
+
if (c.type === "boolean") {
|
|
740
|
+
const b = asBoolean(v);
|
|
741
|
+
out.push(b === null ? csvField(guardText(asText(v))) : b ? "TRUE" : "FALSE");
|
|
742
|
+
continue;
|
|
743
|
+
}
|
|
744
|
+
out.push(csvField(guardText(asText(v))));
|
|
745
|
+
}
|
|
746
|
+
lines.push(out.join(","));
|
|
747
|
+
}
|
|
748
|
+
return "\uFEFF" + lines.join("\r\n") + "\r\n";
|
|
749
|
+
}
|
|
750
|
+
function guardText(s) {
|
|
751
|
+
return FORMULA_START_RE.test(s) ? "'" + s : s;
|
|
752
|
+
}
|
|
753
|
+
var XML_BAD_RE = /[\u0000-\u0008\u000B\u000C\u000E-\u001F\uFFFE\uFFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?<![\uD800-\uDBFF])[\uDC00-\uDFFF]/g;
|
|
754
|
+
function xmlText(s) {
|
|
755
|
+
return s.replace(XML_BAD_RE, "").replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
756
|
+
}
|
|
757
|
+
function columnLetters(ci) {
|
|
758
|
+
let s = "", n = ci + 1;
|
|
759
|
+
while (n > 0) {
|
|
760
|
+
const r = (n - 1) % 26;
|
|
761
|
+
s = String.fromCharCode(65 + r) + s;
|
|
762
|
+
n = Math.floor((n - 1) / 26);
|
|
763
|
+
}
|
|
764
|
+
return s;
|
|
765
|
+
}
|
|
766
|
+
function sheetName(title) {
|
|
767
|
+
let s = String(title ?? "").replace(/[\[\]:*?/\\]/g, " ").replace(XML_BAD_RE, "").replace(/\s+/g, " ").trim();
|
|
768
|
+
s = s.replace(/^'+|'+$/g, "").trim();
|
|
769
|
+
if (s.length > 31) s = s.slice(0, 31).trim();
|
|
770
|
+
if (!s || s.toLowerCase() === "history") s = "Data";
|
|
771
|
+
return s;
|
|
772
|
+
}
|
|
773
|
+
function exportFileName(title, format) {
|
|
774
|
+
let s = String(title ?? "").replace(XML_BAD_RE, "").replace(/[<>:"/\\|?*\u0000-\u001F]/g, " ").replace(/\s+/g, " ").trim();
|
|
775
|
+
s = s.replace(/[. ]+$/, "");
|
|
776
|
+
if (s.length > 80) s = s.slice(0, 80).trim();
|
|
777
|
+
if (!s || /^(con|prn|aux|nul|com\d|lpt\d)$/i.test(s)) s = "table";
|
|
778
|
+
return s + "." + format;
|
|
779
|
+
}
|
|
780
|
+
function tableToXlsx(table) {
|
|
781
|
+
const cols = table.columns.slice(0, XLSX_MAX_COLS);
|
|
782
|
+
const rows = table.rows.slice(0, XLSX_MAX_ROWS - 1);
|
|
783
|
+
const nC = cols.length;
|
|
784
|
+
const numFmtIds = {};
|
|
785
|
+
const numFmtList = [];
|
|
786
|
+
const xfFor = {};
|
|
787
|
+
const XF_DATE = 2, XF_DATETIME = 3;
|
|
788
|
+
let nextXf = 4;
|
|
789
|
+
const colXf = [];
|
|
790
|
+
const colTime = [];
|
|
791
|
+
for (let ci = 0; ci < nC; ci++) {
|
|
792
|
+
const c = cols[ci];
|
|
793
|
+
colTime.push(c.type === "date" && columnUsesTime({ columns: cols, rows }, ci));
|
|
794
|
+
if (c.type === "number") {
|
|
795
|
+
const vals = [];
|
|
796
|
+
for (const r of rows) {
|
|
797
|
+
const n = asNumber(r[ci]);
|
|
798
|
+
if (n !== null) vals.push(n);
|
|
799
|
+
}
|
|
800
|
+
const code = excelNumberFormat(c, vals);
|
|
801
|
+
if (code) {
|
|
802
|
+
if (numFmtIds[code] === void 0) {
|
|
803
|
+
numFmtIds[code] = 164 + numFmtList.length;
|
|
804
|
+
numFmtList.push(code);
|
|
805
|
+
}
|
|
806
|
+
if (xfFor[code] === void 0) xfFor[code] = nextXf++;
|
|
807
|
+
colXf.push(xfFor[code]);
|
|
808
|
+
} else colXf.push(0);
|
|
809
|
+
} else if (c.type === "date") colXf.push(colTime[ci] ? XF_DATETIME : XF_DATE);
|
|
810
|
+
else colXf.push(0);
|
|
811
|
+
}
|
|
812
|
+
const widths = cols.map((c) => Math.min(60, String(c.name).length + 3));
|
|
813
|
+
const sheetRows = [];
|
|
814
|
+
const ref = (ci, ri) => columnLetters(ci) + (ri + 1);
|
|
815
|
+
const head = [];
|
|
816
|
+
for (let ci = 0; ci < nC; ci++) head.push(inlineStr(ref(ci, 0), cols[ci].name, 1));
|
|
817
|
+
sheetRows.push('<row r="1">' + head.join("") + "</row>");
|
|
818
|
+
for (let ri = 0; ri < rows.length; ri++) {
|
|
819
|
+
const row = rows[ri], cells = [];
|
|
820
|
+
for (let ci = 0; ci < nC; ci++) {
|
|
821
|
+
const out = cellXml(cols[ci], row[ci], ref(ci, ri + 1), colXf[ci], colTime[ci]);
|
|
822
|
+
if (!out) continue;
|
|
823
|
+
cells.push(out.xml);
|
|
824
|
+
if (out.width > widths[ci]) widths[ci] = Math.min(60, out.width);
|
|
825
|
+
}
|
|
826
|
+
sheetRows.push('<row r="' + (ri + 2) + '">' + cells.join("") + "</row>");
|
|
827
|
+
}
|
|
828
|
+
const lastRef = nC ? columnLetters(nC - 1) + (rows.length + 1) : "A1";
|
|
829
|
+
const colsXml = nC ? "<cols>" + widths.map((w, ci) => '<col min="' + (ci + 1) + '" max="' + (ci + 1) + '" width="' + Math.max(8, Math.round(w + 1)) + '" customWidth="1"/>').join("") + "</cols>" : "";
|
|
830
|
+
const name = sheetName(table.title);
|
|
831
|
+
const sheetXml = XML_HEAD + '<worksheet xmlns="' + NS_MAIN + '" xmlns:r="' + NS_REL + '"><dimension ref="A1:' + lastRef + '"/><sheetViews><sheetView tabSelected="1" workbookViewId="0">' + (nC ? '<pane ySplit="1" topLeftCell="A2" activePane="bottomLeft" state="frozen"/><selection pane="bottomLeft" activeCell="A2" sqref="A2"/>' : "") + '</sheetView></sheetViews><sheetFormatPr defaultRowHeight="15"/>' + colsXml + "<sheetData>" + sheetRows.join("") + "</sheetData>" + (nC ? '<autoFilter ref="A1:' + lastRef + '"/>' : "") + "</worksheet>";
|
|
832
|
+
const workbookXml = XML_HEAD + '<workbook xmlns="' + NS_MAIN + '" xmlns:r="' + NS_REL + '"><bookViews><workbookView/></bookViews><sheets><sheet name="' + xmlText(name) + '" sheetId="1" r:id="rId1"/></sheets>' + (nC ? '<definedNames><definedName name="_xlnm._FilterDatabase" localSheetId="0" hidden="1">' + xmlText("'" + name.replace(/'/g, "''") + "'!$A$1:$" + columnLetters(nC - 1) + "$" + (rows.length + 1)) + "</definedName></definedNames>" : "") + "</workbook>";
|
|
833
|
+
const numFmtsXml = numFmtList.length ? '<numFmts count="' + numFmtList.length + '">' + numFmtList.map((code) => '<numFmt numFmtId="' + numFmtIds[code] + '" formatCode="' + xmlText(code) + '"/>').join("") + "</numFmts>" : "";
|
|
834
|
+
const xfs = [
|
|
835
|
+
'<xf numFmtId="0" fontId="0" fillId="0" borderId="0" xfId="0"/>',
|
|
836
|
+
'<xf numFmtId="0" fontId="1" fillId="0" borderId="0" xfId="0" applyFont="1"/>',
|
|
837
|
+
'<xf numFmtId="14" fontId="0" fillId="0" borderId="0" xfId="0" applyNumberFormat="1"/>',
|
|
838
|
+
'<xf numFmtId="22" fontId="0" fillId="0" borderId="0" xfId="0" applyNumberFormat="1"/>'
|
|
839
|
+
];
|
|
840
|
+
for (const code of numFmtList) xfs[xfFor[code]] = '<xf numFmtId="' + numFmtIds[code] + '" fontId="0" fillId="0" borderId="0" xfId="0" applyNumberFormat="1"/>';
|
|
841
|
+
const stylesXml = XML_HEAD + '<styleSheet xmlns="' + NS_MAIN + '">' + numFmtsXml + '<fonts count="2"><font><sz val="11"/><name val="Calibri"/><family val="2"/></font><font><b/><sz val="11"/><name val="Calibri"/><family val="2"/></font></fonts><fills count="2"><fill><patternFill patternType="none"/></fill><fill><patternFill patternType="gray125"/></fill></fills><borders count="1"><border><left/><right/><top/><bottom/><diagonal/></border></borders><cellStyleXfs count="1"><xf numFmtId="0" fontId="0" fillId="0" borderId="0"/></cellStyleXfs><cellXfs count="' + xfs.length + '">' + xfs.join("") + '</cellXfs><cellStyles count="1"><cellStyle name="Normal" xfId="0" builtinId="0"/></cellStyles></styleSheet>';
|
|
842
|
+
const contentTypes = XML_HEAD + '<Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types"><Default Extension="rels" ContentType="application/vnd.openxmlformats-package.relationships+xml"/><Default Extension="xml" ContentType="application/xml"/><Override PartName="/xl/workbook.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml"/><Override PartName="/xl/worksheets/sheet1.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml"/><Override PartName="/xl/styles.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml"/></Types>';
|
|
843
|
+
const rootRels = XML_HEAD + '<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships"><Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument" Target="xl/workbook.xml"/></Relationships>';
|
|
844
|
+
const workbookRels = XML_HEAD + '<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships"><Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet" Target="worksheets/sheet1.xml"/><Relationship Id="rId2" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles" Target="styles.xml"/></Relationships>';
|
|
845
|
+
return zipStored([
|
|
846
|
+
["[Content_Types].xml", contentTypes],
|
|
847
|
+
["_rels/.rels", rootRels],
|
|
848
|
+
["xl/workbook.xml", workbookXml],
|
|
849
|
+
["xl/_rels/workbook.xml.rels", workbookRels],
|
|
850
|
+
["xl/styles.xml", stylesXml],
|
|
851
|
+
["xl/worksheets/sheet1.xml", sheetXml]
|
|
852
|
+
]);
|
|
853
|
+
}
|
|
854
|
+
var XML_HEAD = '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>\n';
|
|
855
|
+
var NS_MAIN = "http://schemas.openxmlformats.org/spreadsheetml/2006/main";
|
|
856
|
+
var NS_REL = "http://schemas.openxmlformats.org/officeDocument/2006/relationships";
|
|
857
|
+
function inlineStr(r, text2, style) {
|
|
858
|
+
let s = String(text2);
|
|
859
|
+
if (s.length > XLSX_MAX_CELL_CHARS) s = s.slice(0, XLSX_MAX_CELL_CHARS);
|
|
860
|
+
return '<c r="' + r + '"' + (style ? ' s="' + style + '"' : "") + ' t="inlineStr"><is><t xml:space="preserve">' + xmlText(s) + "</t></is></c>";
|
|
861
|
+
}
|
|
862
|
+
function cellXml(c, v, r, xf, withTime) {
|
|
863
|
+
if (isBlank(v)) return null;
|
|
864
|
+
if (c.type === "number") {
|
|
865
|
+
const n = asNumber(v);
|
|
866
|
+
if (n !== null) return { xml: '<c r="' + r + '"' + (xf ? ' s="' + xf + '"' : "") + "><v>" + String(n) + "</v></c>", width: String(n).length + (Math.abs(n) >= 1e3 ? Math.floor(Math.log10(Math.abs(n)) / 3) : 0) + 2 };
|
|
867
|
+
} else if (c.type === "date") {
|
|
868
|
+
const t = asTime(v);
|
|
869
|
+
if (t !== null && t >= EXCEL_FIRST_DAY) return { xml: '<c r="' + r + '" s="' + xf + '"><v>' + String(excelSerial(t)) + "</v></c>", width: withTime ? 18 : 12 };
|
|
870
|
+
if (t !== null) {
|
|
871
|
+
const s2 = withTime ? isoDayTime(t) : isoDay(t);
|
|
872
|
+
return { xml: inlineStr(r, s2, 0), width: s2.length + 1 };
|
|
873
|
+
}
|
|
874
|
+
} else if (c.type === "boolean") {
|
|
875
|
+
const b = asBoolean(v);
|
|
876
|
+
if (b !== null) return { xml: '<c r="' + r + '" t="b"><v>' + (b ? 1 : 0) + "</v></c>", width: 7 };
|
|
877
|
+
}
|
|
878
|
+
const s = asText(v);
|
|
879
|
+
return { xml: inlineStr(r, s, 0), width: Math.min(60, longestLine(s) + 1) };
|
|
880
|
+
}
|
|
881
|
+
function longestLine(s) {
|
|
882
|
+
let mx = 0;
|
|
883
|
+
for (const line of s.split(/\r?\n/)) if (line.length > mx) mx = line.length;
|
|
884
|
+
return mx;
|
|
885
|
+
}
|
|
886
|
+
var CRC_TABLE = null;
|
|
887
|
+
function crc32(bytes) {
|
|
888
|
+
if (!CRC_TABLE) {
|
|
889
|
+
CRC_TABLE = new Uint32Array(256);
|
|
890
|
+
for (let n = 0; n < 256; n++) {
|
|
891
|
+
let c = n;
|
|
892
|
+
for (let k = 0; k < 8; k++) c = c & 1 ? 3988292384 ^ c >>> 1 : c >>> 1;
|
|
893
|
+
CRC_TABLE[n] = c >>> 0;
|
|
894
|
+
}
|
|
895
|
+
}
|
|
896
|
+
let crc = 4294967295;
|
|
897
|
+
for (let i = 0; i < bytes.length; i++) crc = CRC_TABLE[(crc ^ bytes[i]) & 255] ^ crc >>> 8;
|
|
898
|
+
return (crc ^ 4294967295) >>> 0;
|
|
899
|
+
}
|
|
900
|
+
function utf8(s) {
|
|
901
|
+
return new TextEncoder().encode(s);
|
|
902
|
+
}
|
|
903
|
+
function zipStored(files) {
|
|
904
|
+
const DOS_TIME = 0, DOS_DATE = 0 << 9 | 1 << 5 | 1;
|
|
905
|
+
const locals = [], centrals = [];
|
|
906
|
+
let offset = 0;
|
|
907
|
+
for (const [name, content] of files) {
|
|
908
|
+
const nameBytes = utf8(name);
|
|
909
|
+
const data = typeof content === "string" ? utf8(content) : content;
|
|
910
|
+
const crc = crc32(data);
|
|
911
|
+
const local = new Uint8Array(30 + nameBytes.length);
|
|
912
|
+
const lv = new DataView(local.buffer);
|
|
913
|
+
lv.setUint32(0, 67324752, true);
|
|
914
|
+
lv.setUint16(4, 20, true);
|
|
915
|
+
lv.setUint16(6, 2048, true);
|
|
916
|
+
lv.setUint16(8, 0, true);
|
|
917
|
+
lv.setUint16(10, DOS_TIME, true);
|
|
918
|
+
lv.setUint16(12, DOS_DATE, true);
|
|
919
|
+
lv.setUint32(14, crc, true);
|
|
920
|
+
lv.setUint32(18, data.length, true);
|
|
921
|
+
lv.setUint32(22, data.length, true);
|
|
922
|
+
lv.setUint16(26, nameBytes.length, true);
|
|
923
|
+
lv.setUint16(28, 0, true);
|
|
924
|
+
local.set(nameBytes, 30);
|
|
925
|
+
const central = new Uint8Array(46 + nameBytes.length);
|
|
926
|
+
const cv = new DataView(central.buffer);
|
|
927
|
+
cv.setUint32(0, 33639248, true);
|
|
928
|
+
cv.setUint16(4, 20, true);
|
|
929
|
+
cv.setUint16(6, 20, true);
|
|
930
|
+
cv.setUint16(8, 2048, true);
|
|
931
|
+
cv.setUint16(10, 0, true);
|
|
932
|
+
cv.setUint16(12, DOS_TIME, true);
|
|
933
|
+
cv.setUint16(14, DOS_DATE, true);
|
|
934
|
+
cv.setUint32(16, crc, true);
|
|
935
|
+
cv.setUint32(20, data.length, true);
|
|
936
|
+
cv.setUint32(24, data.length, true);
|
|
937
|
+
cv.setUint16(28, nameBytes.length, true);
|
|
938
|
+
cv.setUint16(30, 0, true);
|
|
939
|
+
cv.setUint16(32, 0, true);
|
|
940
|
+
cv.setUint16(34, 0, true);
|
|
941
|
+
cv.setUint16(36, 0, true);
|
|
942
|
+
cv.setUint32(38, 0, true);
|
|
943
|
+
cv.setUint32(42, offset, true);
|
|
944
|
+
central.set(nameBytes, 46);
|
|
945
|
+
locals.push(local, data);
|
|
946
|
+
centrals.push(central);
|
|
947
|
+
offset += local.length + data.length;
|
|
948
|
+
}
|
|
949
|
+
const centralSize = centrals.reduce((s, c) => s + c.length, 0);
|
|
950
|
+
const end = new Uint8Array(22);
|
|
951
|
+
const ev = new DataView(end.buffer);
|
|
952
|
+
ev.setUint32(0, 101010256, true);
|
|
953
|
+
ev.setUint16(4, 0, true);
|
|
954
|
+
ev.setUint16(6, 0, true);
|
|
955
|
+
ev.setUint16(8, files.length, true);
|
|
956
|
+
ev.setUint16(10, files.length, true);
|
|
957
|
+
ev.setUint32(12, centralSize, true);
|
|
958
|
+
ev.setUint32(16, offset, true);
|
|
959
|
+
ev.setUint16(20, 0, true);
|
|
960
|
+
const total = offset + centralSize + end.length;
|
|
961
|
+
const out = new Uint8Array(total);
|
|
962
|
+
let at = 0;
|
|
963
|
+
for (const part of locals) {
|
|
964
|
+
out.set(part, at);
|
|
965
|
+
at += part.length;
|
|
966
|
+
}
|
|
967
|
+
for (const part of centrals) {
|
|
968
|
+
out.set(part, at);
|
|
969
|
+
at += part.length;
|
|
970
|
+
}
|
|
971
|
+
out.set(end, at);
|
|
972
|
+
return out;
|
|
973
|
+
}
|
|
974
|
+
function buildExportFile(table, format) {
|
|
975
|
+
const name = exportFileName(table.title, format);
|
|
976
|
+
if (format === "csv") {
|
|
977
|
+
const text2 = tableToCsv(table);
|
|
978
|
+
return { name, format, mime: CSV_MIME + ";charset=utf-8", bytes: utf8(text2), text: text2, table };
|
|
979
|
+
}
|
|
980
|
+
return { name, format, mime: XLSX_MIME, bytes: tableToXlsx(table), table };
|
|
981
|
+
}
|
|
982
|
+
function bytesToBase64(bytes) {
|
|
983
|
+
const A = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
|
984
|
+
let out = "";
|
|
985
|
+
let i = 0;
|
|
986
|
+
for (; i + 2 < bytes.length; i += 3) {
|
|
987
|
+
const n = bytes[i] << 16 | bytes[i + 1] << 8 | bytes[i + 2];
|
|
988
|
+
out += A[n >> 18 & 63] + A[n >> 12 & 63] + A[n >> 6 & 63] + A[n & 63];
|
|
989
|
+
}
|
|
990
|
+
const rest = bytes.length - i;
|
|
991
|
+
if (rest === 1) {
|
|
992
|
+
const n = bytes[i] << 16;
|
|
993
|
+
out += A[n >> 18 & 63] + A[n >> 12 & 63] + "==";
|
|
994
|
+
} else if (rest === 2) {
|
|
995
|
+
const n = bytes[i] << 16 | bytes[i + 1] << 8;
|
|
996
|
+
out += A[n >> 18 & 63] + A[n >> 12 & 63] + A[n >> 6 & 63] + "=";
|
|
997
|
+
}
|
|
998
|
+
return out;
|
|
999
|
+
}
|
|
1000
|
+
function exportFormatsFor(hostFormats) {
|
|
1001
|
+
if (!Array.isArray(hostFormats)) return EXPORT_FORMATS.slice();
|
|
1002
|
+
return EXPORT_FORMATS.filter((f2) => hostFormats.indexOf(f2) >= 0);
|
|
1003
|
+
}
|
|
1004
|
+
function exportTableService(save, formats = EXPORT_FORMATS) {
|
|
1005
|
+
const allowed = formats.slice();
|
|
1006
|
+
return async (table, format) => {
|
|
1007
|
+
try {
|
|
1008
|
+
if (!table || !Array.isArray(table.columns) || !Array.isArray(table.rows)) return false;
|
|
1009
|
+
if (allowed.indexOf(format) < 0) return false;
|
|
1010
|
+
const file = buildExportFile(table, format);
|
|
1011
|
+
const res = await save(file);
|
|
1012
|
+
return res !== false;
|
|
1013
|
+
} catch {
|
|
1014
|
+
return false;
|
|
1015
|
+
}
|
|
1016
|
+
};
|
|
1017
|
+
}
|
|
1018
|
+
function browserSaveFile(doc) {
|
|
1019
|
+
return (file) => {
|
|
1020
|
+
const d = doc ?? (typeof document !== "undefined" ? document : void 0);
|
|
1021
|
+
const view = d?.defaultView;
|
|
1022
|
+
const U = view?.URL ?? (typeof URL !== "undefined" ? URL : void 0);
|
|
1023
|
+
const B = view?.Blob ?? (typeof Blob !== "undefined" ? Blob : void 0);
|
|
1024
|
+
if (!d || !d.body || !U || typeof U.createObjectURL !== "function" || !B) return false;
|
|
1025
|
+
const blob = new B([file.bytes.slice()], { type: file.mime });
|
|
1026
|
+
const href = U.createObjectURL(blob);
|
|
1027
|
+
const a = d.createElement("a");
|
|
1028
|
+
a.href = href;
|
|
1029
|
+
a.download = file.name;
|
|
1030
|
+
a.rel = "noopener";
|
|
1031
|
+
a.style.display = "none";
|
|
1032
|
+
d.body.appendChild(a);
|
|
1033
|
+
try {
|
|
1034
|
+
a.click();
|
|
1035
|
+
} finally {
|
|
1036
|
+
a.remove();
|
|
1037
|
+
setTimeout(() => {
|
|
1038
|
+
try {
|
|
1039
|
+
U.revokeObjectURL(href);
|
|
1040
|
+
} catch {
|
|
1041
|
+
}
|
|
1042
|
+
}, 3e4);
|
|
1043
|
+
}
|
|
1044
|
+
return true;
|
|
1045
|
+
};
|
|
1046
|
+
}
|
|
1047
|
+
|
|
556
1048
|
// src/defaults.ts
|
|
1049
|
+
function hostExport(save, formats) {
|
|
1050
|
+
if (typeof save !== "function") return {};
|
|
1051
|
+
const offered = exportFormatsFor(Array.isArray(formats) ? formats : void 0);
|
|
1052
|
+
if (!offered.length) return {};
|
|
1053
|
+
const saveFile = save;
|
|
1054
|
+
return { saveFile, exportFormats: Object.freeze(offered), exportTable: exportTableService(saveFile, offered) };
|
|
1055
|
+
}
|
|
557
1056
|
function themedLand(p) {
|
|
558
1057
|
const bg = p.geoLandColor ? null : toRGBA(p.backgroundColor);
|
|
559
1058
|
if (!bg || bg[3] < 1 || relativeLuminance([bg[0], bg[1], bg[2]]) > 0.2) return void 0;
|
|
@@ -566,6 +1065,7 @@ var numberOr = (raw, dflt) => {
|
|
|
566
1065
|
return Number.isFinite(n) ? n : dflt;
|
|
567
1066
|
};
|
|
568
1067
|
function resolveOptions(p) {
|
|
1068
|
+
const exp = hostExport(p.saveFile, p.exportFormats);
|
|
569
1069
|
return {
|
|
570
1070
|
// ---- host fields: pass through exactly as supplied ----
|
|
571
1071
|
width: p.width,
|
|
@@ -589,6 +1089,15 @@ function resolveOptions(p) {
|
|
|
589
1089
|
dataComplete: p.dataComplete,
|
|
590
1090
|
rowsWithheld: p.rowsWithheld,
|
|
591
1091
|
rowsFilteredOut: p.rowsFilteredOut,
|
|
1092
|
+
// Host services (contract 1.18.0): a FUNCTION or nothing, so a junk value never reaches a chart as something
|
|
1093
|
+
// it would try to call. Passed through untouched otherwise: the host owns what opening or copying means.
|
|
1094
|
+
openUrl: typeof p.openUrl === "function" ? p.openUrl : void 0,
|
|
1095
|
+
copyText: typeof p.copyText === "function" ? p.copyText : void 0,
|
|
1096
|
+
// Exporting rows to a file (contract 1.19.0): exportTable is DERIVED from the host's saveFile, never taken from
|
|
1097
|
+
// the host, so a chart offers an export only where a file can really be kept. See hostExport above.
|
|
1098
|
+
saveFile: exp.saveFile,
|
|
1099
|
+
exportFormats: exp.exportFormats,
|
|
1100
|
+
exportTable: exp.exportTable,
|
|
592
1101
|
// NO LONGER A PASS-THROUGH. A host without a Max Map Points setting used to leave this
|
|
593
1102
|
// undefined, and every map chart then fell back to whatever number its own code carried -
|
|
594
1103
|
// 1000 in every archetype written so far - while the offer gate used the server's. One
|
|
@@ -1767,6 +2276,89 @@ function shapeTest(mark) {
|
|
|
1767
2276
|
};
|
|
1768
2277
|
}
|
|
1769
2278
|
var parseIdxs = (s) => (s || "").split(",").map((x) => parseInt(x, 10)).filter((n) => Number.isFinite(n));
|
|
2279
|
+
var hits = (a, b) => a.l < b.r && b.l < a.r && a.t < b.b && b.t < a.b;
|
|
2280
|
+
var ROW_ASPECT = 3;
|
|
2281
|
+
var LABEL_JOIN = 0.75;
|
|
2282
|
+
var UNDRAWN = /* @__PURE__ */ new Set(["title", "desc", "style", "script", "noscript", "template", "metadata", "textarea", "option"]);
|
|
2283
|
+
function textBoxes(root, skip) {
|
|
2284
|
+
const doc = root.ownerDocument, out = [];
|
|
2285
|
+
const seen = /* @__PURE__ */ new Set();
|
|
2286
|
+
const walker = doc.createTreeWalker(
|
|
2287
|
+
root,
|
|
2288
|
+
4
|
|
2289
|
+
/* NodeFilter.SHOW_TEXT */
|
|
2290
|
+
);
|
|
2291
|
+
let range = null;
|
|
2292
|
+
try {
|
|
2293
|
+
range = doc.createRange();
|
|
2294
|
+
} catch {
|
|
2295
|
+
range = null;
|
|
2296
|
+
}
|
|
2297
|
+
for (let n = walker.nextNode(); n; n = walker.nextNode()) {
|
|
2298
|
+
if (!/\S/.test(n.nodeValue || "")) continue;
|
|
2299
|
+
const p = n.parentElement;
|
|
2300
|
+
if (!p || p.closest(skip)) continue;
|
|
2301
|
+
if (UNDRAWN.has(p.localName.toLowerCase()) || p.closest("defs, clipPath, mask, title, desc")) continue;
|
|
2302
|
+
let r = null;
|
|
2303
|
+
const svgText = p.closest("text");
|
|
2304
|
+
if (svgText) {
|
|
2305
|
+
if (seen.has(svgText)) continue;
|
|
2306
|
+
seen.add(svgText);
|
|
2307
|
+
r = svgText.getBoundingClientRect();
|
|
2308
|
+
} else {
|
|
2309
|
+
try {
|
|
2310
|
+
if (range && typeof range.getBoundingClientRect === "function") {
|
|
2311
|
+
range.selectNodeContents(n);
|
|
2312
|
+
const rr = range.getBoundingClientRect();
|
|
2313
|
+
if (rr && rr.width > 0 && rr.height > 0) r = rr;
|
|
2314
|
+
}
|
|
2315
|
+
} catch {
|
|
2316
|
+
r = null;
|
|
2317
|
+
}
|
|
2318
|
+
if (!r) r = p.getBoundingClientRect();
|
|
2319
|
+
}
|
|
2320
|
+
if (r && r.width > 0 && r.height > 0) out.push({ b: box(r), el: svgText ?? p, node: n });
|
|
2321
|
+
}
|
|
2322
|
+
return out;
|
|
2323
|
+
}
|
|
2324
|
+
function seenRight(el, right, stop) {
|
|
2325
|
+
const win = el.ownerDocument.defaultView;
|
|
2326
|
+
if (!win || el.closest("svg")) return right;
|
|
2327
|
+
for (let a = el; a && a !== stop.parentElement; a = a.parentElement) {
|
|
2328
|
+
try {
|
|
2329
|
+
const o = win.getComputedStyle(a);
|
|
2330
|
+
if (o && o.overflowX && o.overflowX !== "visible") {
|
|
2331
|
+
const r = a.getBoundingClientRect();
|
|
2332
|
+
if (r.width > 0) right = Math.min(right, r.right);
|
|
2333
|
+
}
|
|
2334
|
+
} catch {
|
|
2335
|
+
}
|
|
2336
|
+
if (a === stop) break;
|
|
2337
|
+
}
|
|
2338
|
+
return right;
|
|
2339
|
+
}
|
|
2340
|
+
var SVG_NS = "http://www.w3.org/2000/svg";
|
|
2341
|
+
function overflowWindowOf(el) {
|
|
2342
|
+
const win = el.ownerDocument.defaultView;
|
|
2343
|
+
if (!win || el.namespaceURI === SVG_NS) return null;
|
|
2344
|
+
try {
|
|
2345
|
+
const o = win.getComputedStyle(el);
|
|
2346
|
+
const clips = (v) => !!v && v !== "visible";
|
|
2347
|
+
if (!o || !(clips(o.overflowX) || clips(o.overflowY) || clips(o.overflow))) return null;
|
|
2348
|
+
const r = el.getBoundingClientRect();
|
|
2349
|
+
if (!(r.width > 0 && r.height > 0)) return null;
|
|
2350
|
+
const h = el;
|
|
2351
|
+
const l = r.left + (h.clientLeft || 0), t = r.top + (h.clientTop || 0);
|
|
2352
|
+
const w = h.clientWidth > 0 ? h.clientWidth : r.width, ht = h.clientHeight > 0 ? h.clientHeight : r.height;
|
|
2353
|
+
return { l, t, r: l + w, b: t + ht };
|
|
2354
|
+
} catch {
|
|
2355
|
+
return null;
|
|
2356
|
+
}
|
|
2357
|
+
}
|
|
2358
|
+
var DOT = 8;
|
|
2359
|
+
var RING = 1.5;
|
|
2360
|
+
var DOT_HALF = DOT / 2 + RING;
|
|
2361
|
+
var DOT_IN = 8;
|
|
1770
2362
|
function createAnnotationLayer(container, onClick) {
|
|
1771
2363
|
let list = [];
|
|
1772
2364
|
let report = { shown: 0, notShown: 0 };
|
|
@@ -1785,7 +2377,22 @@ function createAnnotationLayer(container, onClick) {
|
|
|
1785
2377
|
if (win?.requestAnimationFrame) win.requestAnimationFrame(run);
|
|
1786
2378
|
else setTimeout(run, 16);
|
|
1787
2379
|
};
|
|
2380
|
+
const onInnerScroll = () => redrawSoon();
|
|
2381
|
+
const onOuterScroll = (e) => {
|
|
2382
|
+
const t = e.target;
|
|
2383
|
+
if (t && t.nodeType === 1 && t !== container && t.contains(container)) redrawSoon();
|
|
2384
|
+
};
|
|
2385
|
+
let listening = false;
|
|
1788
2386
|
const watch = (on) => {
|
|
2387
|
+
if (on && !listening) {
|
|
2388
|
+
container.addEventListener("scroll", onInnerScroll, { capture: true, passive: true });
|
|
2389
|
+
doc.addEventListener("scroll", onOuterScroll, { capture: true, passive: true });
|
|
2390
|
+
listening = true;
|
|
2391
|
+
} else if (!on && listening) {
|
|
2392
|
+
container.removeEventListener("scroll", onInnerScroll, { capture: true });
|
|
2393
|
+
doc.removeEventListener("scroll", onOuterScroll, { capture: true });
|
|
2394
|
+
listening = false;
|
|
2395
|
+
}
|
|
1789
2396
|
const MO = win?.MutationObserver;
|
|
1790
2397
|
if (on && !observer && MO) {
|
|
1791
2398
|
observer = new MO((records) => {
|
|
@@ -1824,79 +2431,167 @@ function createAnnotationLayer(container, onClick) {
|
|
|
1824
2431
|
const origin = container.getBoundingClientRect();
|
|
1825
2432
|
const open = origin.width > 0 && origin.height > 0 ? box(origin) : FREE;
|
|
1826
2433
|
const clipOf = /* @__PURE__ */ new Map();
|
|
2434
|
+
const windowOf = (el) => {
|
|
2435
|
+
if (!clipOf.has(el)) {
|
|
2436
|
+
if (el.namespaceURI === SVG_NS) {
|
|
2437
|
+
const w = clipWindowOf(el);
|
|
2438
|
+
clipOf.set(el, w && box(w));
|
|
2439
|
+
} else clipOf.set(el, overflowWindowOf(el));
|
|
2440
|
+
}
|
|
2441
|
+
return clipOf.get(el);
|
|
2442
|
+
};
|
|
2443
|
+
let inView = open;
|
|
2444
|
+
if (open !== FREE) for (let el = container.parentElement; inView && el && el !== doc.documentElement && el !== doc.body; el = el.parentElement) {
|
|
2445
|
+
const w = windowOf(el);
|
|
2446
|
+
if (w) inView = cut(inView, w);
|
|
2447
|
+
}
|
|
1827
2448
|
const viewOf = (m) => {
|
|
1828
|
-
let v =
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
|
|
1833
|
-
}
|
|
1834
|
-
for (let el = m.parentElement; v && el && el !== svg && el !== container; el = el.parentElement) {
|
|
1835
|
-
if (!clipOf.has(el)) {
|
|
1836
|
-
const w2 = clipWindowOf(el);
|
|
1837
|
-
clipOf.set(el, w2 && box(w2));
|
|
2449
|
+
let v = inView;
|
|
2450
|
+
for (let el = m.parentElement; v && el && el !== container; el = el.parentElement) {
|
|
2451
|
+
if (el.namespaceURI === SVG_NS && el.localName === "svg") {
|
|
2452
|
+
const s = el.getBoundingClientRect();
|
|
2453
|
+
if (s.width > 0 && s.height > 0) v = cut(v, box(s));
|
|
1838
2454
|
}
|
|
1839
|
-
const w =
|
|
2455
|
+
const w = windowOf(el);
|
|
1840
2456
|
if (w) v = cut(v, w);
|
|
1841
2457
|
}
|
|
1842
2458
|
return v;
|
|
1843
2459
|
};
|
|
1844
2460
|
const controls = Array.from(container.querySelectorAll(`.${CONTROL_CLASS}, .${ZOOM_PAD_CLASS}`)).map((c) => c.getBoundingClientRect()).filter((r) => r.width > 0 && r.height > 0).map(box);
|
|
2461
|
+
let texts = null;
|
|
2462
|
+
const textsNow = () => texts ??= textBoxes(container, `.${ANNOTATION_LAYER_CLASS}, .${CONTROL_CLASS}, .${ZOOM_PAD_CLASS}`);
|
|
2463
|
+
const placed = [];
|
|
2464
|
+
const clampX = (x, hw) => open.l === -Infinity ? x : Math.min(Math.max(x, open.l + hw), Math.max(open.l + hw, open.r - hw));
|
|
2465
|
+
const clampY = (y, hh) => open.t === -Infinity ? y : Math.min(Math.max(y, open.t + hh), Math.max(open.t + hh, open.b - hh));
|
|
2466
|
+
const rowLabel = (v, mark) => {
|
|
2467
|
+
const w = v.r - v.l, h = v.b - v.t;
|
|
2468
|
+
if (!(h > 0) || w < ROW_ASPECT * h) return null;
|
|
2469
|
+
const own = textsNow().filter((t) => {
|
|
2470
|
+
const x = (t.b.l + t.b.r) / 2, y = (t.b.t + t.b.b) / 2;
|
|
2471
|
+
return x > v.l && x < v.r && y > v.t && y < v.b && t.b.b - t.b.t <= h * 1.5;
|
|
2472
|
+
}).sort((p, q) => p.b.l - q.b.l || p.b.t - q.b.t);
|
|
2473
|
+
if (!own.length) return null;
|
|
2474
|
+
const first = own[0];
|
|
2475
|
+
let run = { ...first.b }, seen = mark ? seenRight(first.el, first.b.r, mark) : first.b.r;
|
|
2476
|
+
for (const t of own.slice(1)) {
|
|
2477
|
+
const lineH = run.b - run.t, midY = (t.b.t + t.b.b) / 2;
|
|
2478
|
+
if (midY < run.t || midY > run.b || t.b.l - run.r > LABEL_JOIN * lineH) continue;
|
|
2479
|
+
if (t.b.l < run.r - 1 && t.b.r <= run.r) continue;
|
|
2480
|
+
run = { l: run.l, t: Math.min(run.t, t.b.t), r: Math.max(run.r, t.b.r), b: Math.max(run.b, t.b.b) };
|
|
2481
|
+
seen = Math.max(seen, mark ? seenRight(t.el, t.b.r, mark) : t.b.r);
|
|
2482
|
+
}
|
|
2483
|
+
const after = own.filter((t) => t.b.l >= run.r && t.b.b > run.t && t.b.t < run.b).map((t) => t.b.l);
|
|
2484
|
+
return { r: Math.min(run.r, seen), y: (run.t + run.b) / 2, next: after.length ? Math.min(...after) : v.r };
|
|
2485
|
+
};
|
|
1845
2486
|
const clear = (v, len, mark) => {
|
|
1846
2487
|
const hw = Math.max(16, len * 6 + 8) / 2, hh = 8, g = 2;
|
|
1847
2488
|
const cx = (v.l + v.r) / 2, cy = (v.t + v.b) / 2;
|
|
1848
|
-
const
|
|
1849
|
-
const
|
|
1850
|
-
const
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
2489
|
+
const at = (x, y) => ({ l: x - hw, t: y - hh, r: x + hw, b: y + hh });
|
|
2490
|
+
const free = (x, y) => x >= v.l - hw && x <= v.r + hw && y >= v.t - hh && y <= v.b + hh && controls.every((c) => x + hw <= c.l || x - hw >= c.r || y + hh <= c.t || y - hh >= c.b);
|
|
2491
|
+
const noText = (x, y) => {
|
|
2492
|
+
const b = at(x, y);
|
|
2493
|
+
return textsNow().every((t) => !hits(b, t.b)) && placed.every((p) => !hits(b, p));
|
|
2494
|
+
};
|
|
2495
|
+
const shape = shapeTest(mark);
|
|
2496
|
+
const tries = [];
|
|
2497
|
+
const add = (x, y, px = x, py = y) => tries.push({ x: clampX(x, hw), y: clampY(y, hh), px, py });
|
|
2498
|
+
const label = rowLabel(v, mark);
|
|
2499
|
+
if (label) {
|
|
2500
|
+
const x = label.r + g + hw;
|
|
2501
|
+
if (x + hw <= label.next - g || label.next >= v.r) add(x, label.y, Math.min(x, v.r - 1), label.y);
|
|
2502
|
+
}
|
|
2503
|
+
const ix = Math.max(2, (v.r - v.l) * 0.175), iy = Math.max(2, (v.b - v.t) * 0.175);
|
|
2504
|
+
for (const [kx, ky, sx, sy] of [[v.r, v.t, 1, -1], [v.l, v.t, -1, -1], [v.r, v.b, 1, 1], [v.l, v.b, -1, 1]])
|
|
2505
|
+
for (const k of [0, 0.5, 1]) add(kx + sx * k * hw, ky + sy * k * hh, kx - sx * ix, ky - sy * iy);
|
|
2506
|
+
const grid = [];
|
|
2507
|
+
for (let i = 0; i <= 8; i++) for (let j = 0; j <= 6; j++) grid.push([v.l + (v.r - v.l) * i / 8, v.t + (v.b - v.t) * j / 6]);
|
|
2508
|
+
grid.sort((p, q) => Math.hypot(p[0] - v.r, p[1] - v.t) - Math.hypot(q[0] - v.r, q[1] - v.t));
|
|
2509
|
+
for (const [x, y] of grid) add(x, y);
|
|
2510
|
+
for (const c of controls) for (const [x, y] of [[cx, c.b + hh + g], [cx, c.t - hh - g], [c.l - hw - g, cy], [c.r + hw + g, cy]]) add(x, y);
|
|
2511
|
+
const on = (t) => shape(t.px, t.py);
|
|
2512
|
+
const pick = tries.find((t) => free(t.x, t.y) && noText(t.x, t.y) && on(t)) ?? tries.find((t) => free(t.x, t.y) && noText(t.x, t.y)) ?? tries.find((t) => free(t.x, t.y) && on(t)) ?? tries.find((t) => free(t.x, t.y));
|
|
2513
|
+
if (!pick) return null;
|
|
2514
|
+
placed.push(at(pick.x, pick.y));
|
|
2515
|
+
return [pick.x, pick.y];
|
|
2516
|
+
};
|
|
2517
|
+
const wantsDot = (m) => {
|
|
2518
|
+
const d = m?.closest(`[${NOTE_STYLE_ATTR}]`);
|
|
2519
|
+
return !!d && container.contains(d) && text(d.getAttribute(NOTE_STYLE_ATTR)).toLowerCase() === "dot";
|
|
2520
|
+
};
|
|
2521
|
+
const dotSpot = (v, whole) => {
|
|
2522
|
+
const fits = (b) => b.r - b.l >= 2 * DOT_IN && b.b - b.t >= 2 * DOT_IN;
|
|
2523
|
+
let x, y;
|
|
2524
|
+
if (!fits(whole)) {
|
|
2525
|
+
x = v.r;
|
|
2526
|
+
y = v.t;
|
|
2527
|
+
} else if (fits(v)) {
|
|
2528
|
+
x = v.r - DOT_IN;
|
|
2529
|
+
y = v.t + DOT_IN;
|
|
2530
|
+
} else return null;
|
|
2531
|
+
const e = Math.ceil(DOT_HALF);
|
|
2532
|
+
x = clampX(x, e);
|
|
2533
|
+
y = clampY(y, e);
|
|
2534
|
+
const g = { l: x - DOT_HALF, t: y - DOT_HALF, r: x + DOT_HALF, b: y + DOT_HALF };
|
|
2535
|
+
if (controls.some((c) => hits(g, c))) return null;
|
|
2536
|
+
placed.push(g);
|
|
2537
|
+
return [x, y];
|
|
1855
2538
|
};
|
|
2539
|
+
const offX = -origin.left - (container.clientLeft || 0) + (container.scrollLeft || 0);
|
|
2540
|
+
const offY = -origin.top - (container.clientTop || 0) + (container.scrollTop || 0);
|
|
1856
2541
|
let shown = 0;
|
|
1857
2542
|
for (const a of list) {
|
|
1858
2543
|
const pairs = (a.where ? Object.entries(a.where) : a.column != null ? [[a.column, a.value]] : []).map(([c, v]) => [names.indexOf(c), text(v)]);
|
|
1859
2544
|
const want = pairs.map((p) => p[1]).join(" / ");
|
|
1860
|
-
const
|
|
2545
|
+
const hits2 = /* @__PURE__ */ new Set();
|
|
1861
2546
|
if (pairs.length && pairs.every((p) => p[0] >= 0)) (data.rows || []).forEach((row, r) => {
|
|
1862
|
-
if (pairs.every(([ci, v]) => text(row?.[ci]) === v)) for (const m of marksByRow.get(r) ?? [])
|
|
2547
|
+
if (pairs.every(([ci, v]) => text(row?.[ci]) === v)) for (const m of marksByRow.get(r) ?? []) hits2.add(m);
|
|
1863
2548
|
});
|
|
1864
|
-
if (!
|
|
1865
|
-
let best = null, bestMark = null, laidOut = false;
|
|
1866
|
-
for (const m of
|
|
2549
|
+
if (!hits2.size) continue;
|
|
2550
|
+
let best = null, bestWhole = null, bestMark = null, laidOut = false;
|
|
2551
|
+
for (const m of hits2) {
|
|
1867
2552
|
const b = m.getBoundingClientRect();
|
|
1868
2553
|
if (!(b.width > 0 && b.height > 0)) continue;
|
|
1869
2554
|
laidOut = true;
|
|
1870
2555
|
const v = cut(box(b), viewOf(m));
|
|
1871
2556
|
if (v && (!best || area(v) > area(best))) {
|
|
1872
2557
|
best = v;
|
|
2558
|
+
bestWhole = box(b);
|
|
1873
2559
|
bestMark = m;
|
|
1874
2560
|
}
|
|
1875
2561
|
}
|
|
1876
|
-
const
|
|
2562
|
+
const dot = wantsDot(bestMark ?? hits2.values().next().value ?? null);
|
|
2563
|
+
const pt = !best ? null : dot ? dotSpot(best, bestWhole) : clear(best, (a.label ?? "\u2022").length, bestMark);
|
|
1877
2564
|
if (laidOut && !pt) continue;
|
|
1878
2565
|
shown++;
|
|
1879
2566
|
const badge = doc.createElement("div");
|
|
1880
2567
|
badge.className = ANNOTATION_CLASS;
|
|
1881
|
-
badge.textContent = a.label ?? "\u2022";
|
|
1882
|
-
if (a.title) badge.setAttribute("title", a.title);
|
|
1883
2568
|
badge.setAttribute("role", "button");
|
|
1884
|
-
|
|
2569
|
+
if (dot) {
|
|
2570
|
+
const label = text(a.label), title = text(a.title);
|
|
2571
|
+
badge.setAttribute("title", title ? label ? `(${label}) ${title}` : title : `Note on ${want}${label ? `: ${label}` : ""}`);
|
|
2572
|
+
badge.setAttribute("aria-label", `Note on ${want}${label ? `: ${label}` : ""}${title ? `. ${title}` : ""}`);
|
|
2573
|
+
} else {
|
|
2574
|
+
badge.textContent = a.label ?? "\u2022";
|
|
2575
|
+
if (a.title) badge.setAttribute("title", a.title);
|
|
2576
|
+
badge.setAttribute("aria-label", a.title ? `Note: ${a.title}` : `Note on ${want}`);
|
|
2577
|
+
}
|
|
1885
2578
|
Object.assign(badge.style, {
|
|
1886
2579
|
position: "absolute",
|
|
1887
|
-
left: `${Math.round(pt ? pt[0]
|
|
1888
|
-
top: `${Math.round(pt ? pt[1]
|
|
2580
|
+
left: `${Math.round(pt ? pt[0] + offX : 0)}px`,
|
|
2581
|
+
top: `${Math.round(pt ? pt[1] + offY : 0)}px`,
|
|
1889
2582
|
transform: "translate(-50%, -50%)",
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
2583
|
+
...dot ? { width: `${DOT}px`, height: `${DOT}px`, boxSizing: "border-box", borderRadius: "50%" } : {
|
|
2584
|
+
minWidth: "16px",
|
|
2585
|
+
height: "16px",
|
|
2586
|
+
padding: "0 4px",
|
|
2587
|
+
boxSizing: "border-box",
|
|
2588
|
+
borderRadius: "8px",
|
|
2589
|
+
font: "600 10px/16px system-ui, sans-serif",
|
|
2590
|
+
textAlign: "center",
|
|
2591
|
+
color: theme.bg || "#ffffff"
|
|
2592
|
+
},
|
|
1898
2593
|
background: theme.accent || theme.fg || "#0f6cbd",
|
|
1899
|
-
boxShadow: `0 0 0
|
|
2594
|
+
boxShadow: `0 0 0 ${RING}px ${theme.bg || "#ffffff"}`,
|
|
1900
2595
|
cursor: onClick ? "pointer" : "default",
|
|
1901
2596
|
// Never pointer-events (a host failsafe turns it back on); visibility hides a badge whose mark
|
|
1902
2597
|
// has no box yet.
|
|
@@ -3134,6 +3829,20 @@ export {
|
|
|
3134
3829
|
autoRampMinStep,
|
|
3135
3830
|
autoRampCanvas,
|
|
3136
3831
|
resolveAutoColorScale,
|
|
3832
|
+
EXPORT_FORMATS,
|
|
3833
|
+
XLSX_MIME,
|
|
3834
|
+
CSV_MIME,
|
|
3835
|
+
excelSerial,
|
|
3836
|
+
excelNumberFormat,
|
|
3837
|
+
tableToCsv,
|
|
3838
|
+
sheetName,
|
|
3839
|
+
exportFileName,
|
|
3840
|
+
tableToXlsx,
|
|
3841
|
+
buildExportFile,
|
|
3842
|
+
bytesToBase64,
|
|
3843
|
+
exportFormatsFor,
|
|
3844
|
+
exportTableService,
|
|
3845
|
+
browserSaveFile,
|
|
3137
3846
|
resolveOptions,
|
|
3138
3847
|
geoAssetFor,
|
|
3139
3848
|
loadGeo,
|