@martinomagnifico/tablechart 1.2.2 → 1.2.3
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/CHANGELOG.md +29 -0
- package/dist/tablechart-additional-types.d.mts +1 -1
- package/dist/tablechart-additional-types.mjs +70 -70
- package/dist/tablechart-core.d.mts +2 -2
- package/dist/tablechart-core.mjs +1 -1
- package/dist/tablechart-shared.d.mts +5 -1
- package/dist/tablechart-shared.mjs +823 -763
- package/dist/tablechart-summary.mjs +10 -10
- package/dist/tablechart.css +1 -1
- package/dist/tablechart.d.mts +1 -1
- package/dist/tablechart.js +1 -1
- package/dist/tablechart.mjs +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,34 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [1.2.3] - 2026-10-31
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
|
|
7
|
+
- `checkContrast` and `checkTextContrast` in `@martinomagnifico/tablechart/core`. A script that builds its own charts, can check their contrast too.
|
|
8
|
+
- `--tablechart-value-on-dark` and `--tablechart-value-on-light`, the two colours a number inside a bar chooses from, such as ivory and navy. If neither has enough contrast with the bar, the number gets to be black or white.
|
|
9
|
+
- `--tablechart-value-contrast`, the contrast a number inside a bar needs: 5:1 by default, a little more than the 4.5:1 that WCAG asks, so it is easier to read.
|
|
10
|
+
- `--tablechart-contrast-wcag: 3` measures contrast with APCA, from the draft of WCAG 3, for the number colours and the warnings alike. It follows what people see more closely than WCAG 2, which stays the default.
|
|
11
|
+
- `--tablechart-marker-ease`, the easing with which a scatter marker grows. With a `linear()` curve, markers can bounce in.
|
|
12
|
+
|
|
13
|
+
### Changed
|
|
14
|
+
|
|
15
|
+
- Tablechart measures the background behind a chart, such as a card or a slide, so `--tablechart-surface` is only needed on an image or a gradient. Before, a chart in a card needed it by hand.
|
|
16
|
+
- The contrast check runs for every chart, not only with `debug`. A printed page or a PDF has the same colours as the screen.
|
|
17
|
+
|
|
18
|
+
### Deprecated
|
|
19
|
+
|
|
20
|
+
- `--tablechart-bar-value-color`, `-piece-`, `-up-`, `-down-` and `-total-value-color` still work, but go in 1.3.0, and the console warns about them. They set one colour without a contrast check; `--tablechart-value-on-dark` and `--tablechart-value-on-light` replace them.
|
|
21
|
+
|
|
22
|
+
### Fixed
|
|
23
|
+
|
|
24
|
+
- A chart whose width changes is laid out before the next frame is shown. Before, it was shown scaled for a frame or two, so the page jumped.
|
|
25
|
+
- After a chart is built, a change of colour, such as to dark mode, changes its text at once. Before, the text took the time of the whole build again.
|
|
26
|
+
- A scatter chart keeps the room it needs before it is laid out. Before, the page moved down by about a third of its width when it appeared.
|
|
27
|
+
- On a scatter chart with steps, a marker grows at its step. Before, it only faded in, because it had grown while still hidden.
|
|
28
|
+
- A chart with steps and gridlines or a quadrant builds smoothly in Safari. Its lines now stop around the text as they do without steps; the mask they had made Safari draw the chart again on every frame.
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
|
|
3
32
|
## [1.2.2] - 2026-10-30
|
|
4
33
|
|
|
5
34
|
### Added
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { y as scatter } from "./tablechart-shared.mjs";
|
|
2
2
|
export { scatter };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { A as e, C as t, E as n, F as r, I as i,
|
|
1
|
+
import { A as e, C as t, E as n, F as r, I as i, K as a, L as o, M as s, N as c, O as l, R as u, S as d, T as f, U as p, V as m, j as h, w as g } from "./tablechart-shared.mjs";
|
|
2
2
|
// src/js/annotations/quadrant.ts
|
|
3
|
-
var _ = `${
|
|
3
|
+
var _ = `${p}-name`, v = [
|
|
4
4
|
"top left",
|
|
5
5
|
"top right",
|
|
6
6
|
"bottom left",
|
|
@@ -17,26 +17,26 @@ var _ = `${l}-name`, v = [
|
|
|
17
17
|
}, b = {
|
|
18
18
|
create(e, t) {
|
|
19
19
|
for (let n of e.querySelectorAll("[data-corner]")) {
|
|
20
|
-
let e = (n.getAttribute("data-corner") ?? "").toLowerCase().split(/\s+/),
|
|
21
|
-
if (!v.includes(
|
|
22
|
-
console.warn(`[${
|
|
20
|
+
let e = (n.getAttribute("data-corner") ?? "").toLowerCase().split(/\s+/), r = `${e.find((e) => e === "top" || e === "bottom")} ${e.find((e) => e === "left" || e === "right")}`;
|
|
21
|
+
if (!v.includes(r)) {
|
|
22
|
+
console.warn(`[${o}] A quadrant has a corner "${n.getAttribute("data-corner")}". It takes ${v.join(", ")}.`);
|
|
23
23
|
continue;
|
|
24
24
|
}
|
|
25
|
-
let
|
|
26
|
-
if (
|
|
27
|
-
else
|
|
28
|
-
for (let { name: e, value: t } of Array.from(n.attributes)) e !== "data-corner" &&
|
|
29
|
-
t.append(
|
|
25
|
+
let i = document.createElement("span");
|
|
26
|
+
if (i.className = _, i.dataset.corner = r, i.inert = !0, n.childElementCount) for (let e of Array.from(n.children)) i.append(e.cloneNode(!0));
|
|
27
|
+
else i.textContent = (n.textContent ?? "").trim();
|
|
28
|
+
for (let { name: e, value: t } of Array.from(n.attributes)) e !== "data-corner" && i.setAttribute(e, t);
|
|
29
|
+
t.append(i);
|
|
30
30
|
}
|
|
31
31
|
return null;
|
|
32
32
|
},
|
|
33
|
-
draw(
|
|
34
|
-
let { frame:
|
|
35
|
-
if (!
|
|
36
|
-
console.warn(`[${
|
|
33
|
+
draw(e, i, l) {
|
|
34
|
+
let { frame: u, x: d, y: f, rows: v, series: b, height: x, unit: S, svg: C, plot: w, categories: T } = l;
|
|
35
|
+
if (!u || !d) {
|
|
36
|
+
console.warn(`[${o}] A quadrant works on a scatter chart, which has an axis across and an axis up.`);
|
|
37
37
|
return;
|
|
38
38
|
}
|
|
39
|
-
let [E, D, O, k] =
|
|
39
|
+
let [E, D, O, k] = u, A = b.flatMap((e, t) => e.group ? [] : [t]), j = (e) => v.flatMap((t) => t.cells[A[e]] && !t.cells[A[e]].missing ? [t.cells[A[e]].value] : []), M = y(e.getAttribute("data-x"), j(0)), N = y(e.getAttribute("data-y"), j(1)), P = M === null ? E + O / 2 : Math.min(Math.max(d(M), E), E + O), F = N === null ? D + k / 2 : Math.min(Math.max(f(N), D), D + k), I = C.querySelector(`:scope > .${r}`);
|
|
40
40
|
if (I) {
|
|
41
41
|
let e = (e, t) => Math.abs(e - t) < S / 2, t = (I.getAttribute("d") ?? "").match(/M[^M]+/g) ?? [];
|
|
42
42
|
I.setAttribute("d", t.filter((t) => {
|
|
@@ -44,27 +44,27 @@ var _ = `${l}-name`, v = [
|
|
|
44
44
|
return !(i === "V" && e(Number(n), P)) && !(i === "H" && e(Number(r), F));
|
|
45
45
|
}).join(""));
|
|
46
46
|
}
|
|
47
|
-
C.insertBefore(
|
|
48
|
-
class:
|
|
49
|
-
d: `M${
|
|
50
|
-
}), C.querySelector(`:scope > .${
|
|
47
|
+
C.insertBefore(c("path", {
|
|
48
|
+
class: p,
|
|
49
|
+
d: `M${s(P)},${s(D)}V${s(D + k)}M${s(E)},${s(F)}H${s(E + O)}`
|
|
50
|
+
}), C.querySelector(`:scope > .${m}`));
|
|
51
51
|
let L = 6 * S, R = [];
|
|
52
52
|
for (let e of w.querySelectorAll(`:scope > .${_}`)) {
|
|
53
|
-
let t = e.dataset.corner ?? "", n = t.includes("right"), r = t.includes("bottom"), i = n ? E + O - L : E + L,
|
|
54
|
-
|
|
55
|
-
let
|
|
53
|
+
let t = e.dataset.corner ?? "", n = t.includes("right"), r = t.includes("bottom"), i = n ? E + O - L : E + L, o = r ? D + k - L : D + L;
|
|
54
|
+
h(e, i, o, a, x);
|
|
55
|
+
let s = g(e).width * S, c = g(e).height * S;
|
|
56
56
|
R.push([
|
|
57
|
-
n ? i -
|
|
58
|
-
r ?
|
|
59
|
-
|
|
60
|
-
|
|
57
|
+
n ? i - s : i,
|
|
58
|
+
r ? o - c : o,
|
|
59
|
+
s,
|
|
60
|
+
c
|
|
61
61
|
]);
|
|
62
62
|
}
|
|
63
|
-
|
|
63
|
+
l.taken.push(...R);
|
|
64
64
|
for (let e of T) {
|
|
65
65
|
if (e.hidden || e.hasAttribute("data-left-out") || !e.style.left) continue;
|
|
66
|
-
let
|
|
67
|
-
R.some((e) =>
|
|
66
|
+
let r = t(e, S, a, x, [0, 0]);
|
|
67
|
+
R.some((e) => n(e, r)) && e.setAttribute("data-left-out", "");
|
|
68
68
|
}
|
|
69
69
|
}
|
|
70
70
|
}, x = [
|
|
@@ -96,13 +96,13 @@ var _ = `${l}-name`, v = [
|
|
|
96
96
|
axes: !0,
|
|
97
97
|
numbers: !1,
|
|
98
98
|
annotations: { quadrant: b },
|
|
99
|
-
text({ figure:
|
|
100
|
-
let { x:
|
|
101
|
-
|
|
102
|
-
let n = T(e,
|
|
99
|
+
text({ figure: t, plot: n, rows: r, series: a, config: o }) {
|
|
100
|
+
let { x: s, y: c, size: l, group: d } = C(a), f = n.querySelector(":scope > .tablechart-categories")?.children ?? [], p = /* @__PURE__ */ new Map();
|
|
101
|
+
r.forEach((e, t) => {
|
|
102
|
+
let n = T(e, s, c);
|
|
103
103
|
n && (p.get(n)?.push(t) ?? p.set(n, [t]));
|
|
104
104
|
});
|
|
105
|
-
let m = (e) =>
|
|
105
|
+
let m = (e) => l === void 0 ? 0 : Math.abs(r[e].cells[l]?.value ?? 0);
|
|
106
106
|
for (let e of p.values()) {
|
|
107
107
|
if (e.length < 2) continue;
|
|
108
108
|
let t = e.reduce((e, t) => m(t) > m(e) ? t : e);
|
|
@@ -111,53 +111,53 @@ var _ = `${l}-name`, v = [
|
|
|
111
111
|
n === t ? r?.setAttribute("data-more", String(e.length - 1)) : r?.setAttribute("data-same", "");
|
|
112
112
|
}
|
|
113
113
|
}
|
|
114
|
-
let h = w(
|
|
115
|
-
if (h.length < 2 &&
|
|
114
|
+
let h = w(r, d);
|
|
115
|
+
if (h.length < 2 && l === void 0) return;
|
|
116
116
|
let g = document.createElement("div");
|
|
117
|
-
g.className =
|
|
118
|
-
let _ = Array.from(
|
|
119
|
-
let
|
|
120
|
-
return
|
|
117
|
+
g.className = i, g.setAttribute("aria-hidden", "true"), g.inert = !0;
|
|
118
|
+
let _ = Array.from(t.querySelectorAll(`tbody tr > td:nth-of-type(${d + 1})`)), v = (t, n) => {
|
|
119
|
+
let r = e(u, g);
|
|
120
|
+
return r.dataset.place = "legend", r.dataset.line = "none", r.textContent = t, n && o.langattribute && r.setAttribute(o.langattribute, n), r;
|
|
121
121
|
};
|
|
122
122
|
h.length > 1 && h.forEach((e, t) => {
|
|
123
|
-
let n =
|
|
123
|
+
let n = o.langattribute ? _.find((t) => t.textContent?.trim() === e)?.getAttribute(o.langattribute) : null, r = v(e, n);
|
|
124
124
|
r.dataset.marker = x[t % x.length], r.style.setProperty("--n", String(t)), r.style.setProperty("--palette", `var(--tablechart-color-${t + 1})`);
|
|
125
|
-
}),
|
|
125
|
+
}), l !== void 0 && (v(a[l].name, a[l].key).dataset.marker = "size"), n.after(g);
|
|
126
126
|
},
|
|
127
|
-
draw(
|
|
128
|
-
let { rows:
|
|
129
|
-
if (!
|
|
130
|
-
let b = C(
|
|
131
|
-
let n = e.cells[b.x],
|
|
132
|
-
if (!n || !
|
|
133
|
-
let
|
|
127
|
+
draw(e) {
|
|
128
|
+
let { rows: t, series: n, x: r, y: i, frame: o, unit: c, svg: u, categories: p, height: _, config: v, plot: y } = e;
|
|
129
|
+
if (!r || !o) return;
|
|
130
|
+
let b = C(n), T = w(t, b.group), E = T.length > 1, D = (e.length("--tablechart-marker-size", "10px") ?? 10 * c) / 2, O = (e.length("--tablechart-bubble-max", "24px") ?? 24 * c) / 2, k = (e.length("--tablechart-bubble-min", "") ?? D * 1.2) / 2, A = (e) => b.size === void 0 ? void 0 : e.cells[b.size], j = l(t.map((e) => Math.abs(A(e)?.value ?? 0))), M = t.flatMap((e, t) => {
|
|
131
|
+
let n = e.cells[b.x], a = e.cells[b.y];
|
|
132
|
+
if (!n || !a || n.missing || a.missing) return [];
|
|
133
|
+
let o = A(e), s = o && !o.missing && j > 0 ? Math.max(k, Math.sqrt(Math.abs(o.value) / j) * O) : D, c = E ? T.indexOf(e.cells[b.group]?.raw ?? "") : -1;
|
|
134
134
|
return [{
|
|
135
135
|
i: t,
|
|
136
|
-
px:
|
|
137
|
-
py:
|
|
138
|
-
r:
|
|
136
|
+
px: r(n.value),
|
|
137
|
+
py: i(a.value),
|
|
138
|
+
r: s,
|
|
139
139
|
g: c
|
|
140
140
|
}];
|
|
141
141
|
}), N = Math.min(M.length - 1, 6);
|
|
142
142
|
y.style.setProperty("--count", String(N + 1));
|
|
143
|
-
let P = new Map([...M].sort((e, t) => e.px - t.px || e.i - t.i).map((
|
|
143
|
+
let P = new Map([...M].sort((e, t) => e.px - t.px || e.i - t.i).map((e, t) => [e.i, N ? s(t * N / (M.length - 1)) : 0])), F = [...M].sort((e, t) => t.r - e.r || e.i - t.i);
|
|
144
144
|
for (let e of F) {
|
|
145
145
|
let t = E ? x[e.g % x.length] : "circle";
|
|
146
|
-
|
|
147
|
-
class:
|
|
146
|
+
u.appendChild(d(t, e.px, e.py, e.r, {
|
|
147
|
+
class: m,
|
|
148
148
|
"data-row": e.i + 1,
|
|
149
149
|
"data-marker": t,
|
|
150
150
|
style: `--i:${P.get(e.i)}; ${E ? `--n:${e.g}; --palette:var(--tablechart-color-${e.g + 1})` : ""}`
|
|
151
151
|
}));
|
|
152
152
|
}
|
|
153
|
-
let I = y.parentElement?.getAttribute("data-chart-names"), L = I == null ? v.names : I !== "false", R = 4 *
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
153
|
+
let I = y.parentElement?.getAttribute("data-chart-names"), L = I == null ? v.names : I !== "false", R = 4 * c, z = [
|
|
154
|
+
o[0] + 1.5 * R,
|
|
155
|
+
o[1],
|
|
156
|
+
o[2] - 1.5 * R,
|
|
157
|
+
o[3] - 1.5 * R
|
|
158
158
|
], [B, V, H, U] = z, W = F.map(({ i: e, px: t, py: n, r }) => {
|
|
159
|
-
if (
|
|
160
|
-
let { width: i, height: a } =
|
|
159
|
+
if (p[e].hasAttribute("data-same")) return [];
|
|
160
|
+
let { width: i, height: a } = g(p[e]), o = i * c, s = a * c, l = s * .1, u = r * .7 + R / 2, d = (e, t) => [
|
|
161
161
|
Math.max(B, Math.min(e, B + H - o)),
|
|
162
162
|
Math.max(V, Math.min(t, V + U - s)) + l,
|
|
163
163
|
o,
|
|
@@ -173,23 +173,23 @@ var _ = `${l}-name`, v = [
|
|
|
173
173
|
d(t + u, n + u),
|
|
174
174
|
d(t - u - o, n + u)
|
|
175
175
|
];
|
|
176
|
-
}), G = L ?
|
|
176
|
+
}), G = L ? f(W, M.map(({ px: e, py: t, r: n }) => [
|
|
177
177
|
e - n,
|
|
178
178
|
t - n,
|
|
179
179
|
2 * n,
|
|
180
180
|
2 * n
|
|
181
181
|
]), z) : F.map(() => null);
|
|
182
|
-
for (let e of
|
|
182
|
+
for (let e of p) e.hidden = !0, e.dataset.missing = "";
|
|
183
183
|
F.forEach((e, t) => {
|
|
184
|
-
let n =
|
|
184
|
+
let n = p[e.i], r = G[t];
|
|
185
185
|
if (n.hidden = !1, delete n.dataset.missing, n.style.setProperty("--i", String(P.get(e.i))), n.toggleAttribute("data-left-out", r === null), r === null) return;
|
|
186
186
|
n.dataset.side = S[r];
|
|
187
|
-
let [i,
|
|
188
|
-
|
|
189
|
-
}),
|
|
190
|
-
let n = null, r = 6 *
|
|
187
|
+
let [i, o, , s] = W[t][r];
|
|
188
|
+
h(n, i, o - (g(n).height * c - s) / 2, a, _);
|
|
189
|
+
}), e.rowAt = (e, t) => {
|
|
190
|
+
let n = null, r = 6 * c;
|
|
191
191
|
for (let i of M) {
|
|
192
|
-
let a = Math.max(Math.hypot(i.px - e *
|
|
192
|
+
let a = Math.max(Math.hypot(i.px - e * c, i.py - t * c) - i.r, 0);
|
|
193
193
|
(a < r || a === r && n && i.r < n.r) && (r = a, n = i);
|
|
194
194
|
}
|
|
195
195
|
return n ? n.i : null;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { A as
|
|
2
|
-
export { AT_ONCE_CLASS, type ChartState, type ChartType, type Config, PLACED_CLASS, PLOT_CLASS, PRINTING_CLASS, QUEUED_CLASS, type Row, SHOWN_CLASS, type Series, type StepPlan, addType, adoptTables, assignKeys, build, defaultConfig, entranceOf, layout, loadSources, prepare, readMarkdownRows, relabel, setShown, stepTo, unbuild };
|
|
1
|
+
import { A as PRINTING_CLASS, C as Series, D as Config, E as AT_ONCE_CLASS, M as SHOWN_CLASS, N as defaultConfig, O as PLACED_CLASS, S as Row, T as stepTo, _ as setShown, a as loadSources, b as ChartState, f as prepare, g as relabel, h as layout, i as adoptTables, j as QUEUED_CLASS, k as PLOT_CLASS, m as build, n as checkTextContrast, o as readMarkdownRows, p as addType, r as assignKeys, t as checkContrast, u as entranceOf, v as unbuild, w as StepPlan, x as ChartType } from "./tablechart-shared.mjs";
|
|
2
|
+
export { AT_ONCE_CLASS, type ChartState, type ChartType, type Config, PLACED_CLASS, PLOT_CLASS, PRINTING_CLASS, QUEUED_CLASS, type Row, SHOWN_CLASS, type Series, type StepPlan, addType, adoptTables, assignKeys, build, checkContrast, checkTextContrast, defaultConfig, entranceOf, layout, loadSources, prepare, readMarkdownRows, relabel, setShown, stepTo, unbuild };
|
package/dist/tablechart-core.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export { P as AT_ONCE_CLASS, z as PLACED_CLASS, B as PLOT_CLASS, H as PRINTING_CLASS, W as QUEUED_CLASS, G as SHOWN_CLASS, u as addType, a as adoptTables, _ as assignKeys, d as build, c as checkContrast, l as checkTextContrast, q as defaultConfig, n as entranceOf, f as layout, o as loadSources, i as prepare, s as readMarkdownRows, p as relabel, m as setShown, g as stepTo, h as unbuild } from "./tablechart-shared.mjs";
|
|
@@ -420,4 +420,8 @@ declare const loadSources: (figures: HTMLElement[]) => Promise<void>;
|
|
|
420
420
|
declare const readMarkdownRows: (figures: HTMLElement[]) => void;
|
|
421
421
|
/** Writes translation keys such as `harvest-row1` onto a figure with `data-chart-keys`; a duplicate prefix gets a number. */
|
|
422
422
|
declare const assignKeys: (figures: HTMLElement[], langattribute: string | false) => void;
|
|
423
|
-
|
|
423
|
+
/** Warns about each line, slice or bar that does not stand out enough from the background. Faint parts that are out of focus are left out. */
|
|
424
|
+
declare const checkContrast: (figure: HTMLElement) => void;
|
|
425
|
+
/** Warns about each number inside a bar whose colour does not stand out enough from that bar, once the chart is built. */
|
|
426
|
+
declare const checkTextContrast: (figure: HTMLElement) => void;
|
|
427
|
+
export { PRINTING_CLASS as A, Series as C, Config as D, AT_ONCE_CLASS as E, SHOWN_CLASS as M, defaultConfig as N, PLACED_CLASS as O, Row as S, stepTo as T, setShown as _, loadSources as a, ChartState as b, TablechartInstance as c, init as d, prepare as f, relabel as g, layout as h, adoptTables as i, QUEUED_CLASS as j, PLOT_CLASS as k, create as l, build as m, checkTextContrast as n, readMarkdownRows as o, addType as p, assignKeys as r, TablechartChart as s, checkContrast as t, entranceOf as u, unbuild as v, StepPlan as w, ChartType as x, scatter as y };
|