@krizaka/charts 0.0.0-stage → 0.1.0
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/LICENSE +202 -0
- package/README.md +47 -2
- package/dist/bar.d.ts +17 -0
- package/dist/bar.js +16 -0
- package/dist/bar.js.map +1 -0
- package/dist/candlestick-IG626XL4.js +13 -0
- package/dist/candlestick-IG626XL4.js.map +1 -0
- package/dist/candlestick.d.ts +42 -0
- package/dist/candlestick.js +13 -0
- package/dist/candlestick.js.map +1 -0
- package/dist/canvas-4MSYDVFO.js +14 -0
- package/dist/canvas-4MSYDVFO.js.map +1 -0
- package/dist/cartesian-BRhNQ3ib.d.ts +34 -0
- package/dist/chart.d.ts +58 -0
- package/dist/chart.js +11 -0
- package/dist/chart.js.map +1 -0
- package/dist/chunk-3CJHBJXA.js +186 -0
- package/dist/chunk-3CJHBJXA.js.map +1 -0
- package/dist/chunk-6FINSUOS.js +49 -0
- package/dist/chunk-6FINSUOS.js.map +1 -0
- package/dist/chunk-7CSAGFBW.js +166 -0
- package/dist/chunk-7CSAGFBW.js.map +1 -0
- package/dist/chunk-7TIFCK5E.js +103 -0
- package/dist/chunk-7TIFCK5E.js.map +1 -0
- package/dist/chunk-AHQXJSAQ.js +38 -0
- package/dist/chunk-AHQXJSAQ.js.map +1 -0
- package/dist/chunk-ANUCSRUN.js +43 -0
- package/dist/chunk-ANUCSRUN.js.map +1 -0
- package/dist/chunk-BISL7DYW.js +66 -0
- package/dist/chunk-BISL7DYW.js.map +1 -0
- package/dist/chunk-BZ5CQFPH.js +19 -0
- package/dist/chunk-BZ5CQFPH.js.map +1 -0
- package/dist/chunk-DWJPPEMC.js +455 -0
- package/dist/chunk-DWJPPEMC.js.map +1 -0
- package/dist/chunk-DZB6HEVO.js +73 -0
- package/dist/chunk-DZB6HEVO.js.map +1 -0
- package/dist/chunk-EK3Z647J.js +133 -0
- package/dist/chunk-EK3Z647J.js.map +1 -0
- package/dist/chunk-I5QUZVU2.js +234 -0
- package/dist/chunk-I5QUZVU2.js.map +1 -0
- package/dist/chunk-OB5EFDDH.js +118 -0
- package/dist/chunk-OB5EFDDH.js.map +1 -0
- package/dist/chunk-OER6ETT4.js +155 -0
- package/dist/chunk-OER6ETT4.js.map +1 -0
- package/dist/chunk-PTSB3H5Q.js +205 -0
- package/dist/chunk-PTSB3H5Q.js.map +1 -0
- package/dist/chunk-TPJDOB7R.js +15 -0
- package/dist/chunk-TPJDOB7R.js.map +1 -0
- package/dist/chunk-UNK4MJVG.js +378 -0
- package/dist/chunk-UNK4MJVG.js.map +1 -0
- package/dist/chunk-VKO2OYYM.js +88 -0
- package/dist/chunk-VKO2OYYM.js.map +1 -0
- package/dist/chunk-VKTZD7UT.js +107 -0
- package/dist/chunk-VKTZD7UT.js.map +1 -0
- package/dist/chunk-W5FX4TU3.js +102 -0
- package/dist/chunk-W5FX4TU3.js.map +1 -0
- package/dist/chunk-WBH2QU77.js +178 -0
- package/dist/chunk-WBH2QU77.js.map +1 -0
- package/dist/chunk-WIRCIOLH.js +145 -0
- package/dist/chunk-WIRCIOLH.js.map +1 -0
- package/dist/chunk-XAJ3KCC4.js +116 -0
- package/dist/chunk-XAJ3KCC4.js.map +1 -0
- package/dist/chunk-XC6BQ3RN.js +92 -0
- package/dist/chunk-XC6BQ3RN.js.map +1 -0
- package/dist/chunk-XLLYNNC6.js +89 -0
- package/dist/chunk-XLLYNNC6.js.map +1 -0
- package/dist/chunk-XR4ZJDOV.js +15 -0
- package/dist/chunk-XR4ZJDOV.js.map +1 -0
- package/dist/context-BgYUymEO.d.ts +163 -0
- package/dist/frame-I7_xYGy5.d.ts +45 -0
- package/dist/full-S2MBPEEP.js +11 -0
- package/dist/full-S2MBPEEP.js.map +1 -0
- package/dist/funnel-QU5ZPC52.js +13 -0
- package/dist/funnel-QU5ZPC52.js.map +1 -0
- package/dist/funnel.d.ts +26 -0
- package/dist/funnel.js +13 -0
- package/dist/funnel.js.map +1 -0
- package/dist/gauge.d.ts +38 -0
- package/dist/gauge.js +12 -0
- package/dist/gauge.js.map +1 -0
- package/dist/geo.d.ts +37 -0
- package/dist/geo.js +13 -0
- package/dist/geo.js.map +1 -0
- package/dist/globe.d.ts +36 -0
- package/dist/globe.js +12 -0
- package/dist/globe.js.map +1 -0
- package/dist/heatmap-JWQOKUGM.js +13 -0
- package/dist/heatmap-JWQOKUGM.js.map +1 -0
- package/dist/heatmap.d.ts +47 -0
- package/dist/heatmap.js +15 -0
- package/dist/heatmap.js.map +1 -0
- package/dist/host-_F8RgiIz.d.ts +15 -0
- package/dist/index.d.ts +22 -0
- package/dist/index.js +101 -0
- package/dist/index.js.map +1 -0
- package/dist/line.d.ts +25 -0
- package/dist/line.js +18 -0
- package/dist/line.js.map +1 -0
- package/dist/native.d.ts +300 -0
- package/dist/native.js +875 -0
- package/dist/native.js.map +1 -0
- package/dist/pie.d.ts +37 -0
- package/dist/pie.js +16 -0
- package/dist/pie.js.map +1 -0
- package/dist/provider.d.ts +73 -0
- package/dist/provider.js +24 -0
- package/dist/provider.js.map +1 -0
- package/dist/radar-75GRJ2IK.js +13 -0
- package/dist/radar-75GRJ2IK.js.map +1 -0
- package/dist/radar.d.ts +22 -0
- package/dist/radar.js +13 -0
- package/dist/radar.js.map +1 -0
- package/dist/sankey-XQTX2EG6.js +13 -0
- package/dist/sankey-XQTX2EG6.js.map +1 -0
- package/dist/sankey.d.ts +28 -0
- package/dist/sankey.js +13 -0
- package/dist/sankey.js.map +1 -0
- package/dist/scatter-XSNG4OKD.js +13 -0
- package/dist/scatter-XSNG4OKD.js.map +1 -0
- package/dist/scatter.d.ts +41 -0
- package/dist/scatter.js +15 -0
- package/dist/scatter.js.map +1 -0
- package/dist/sparkline.d.ts +26 -0
- package/dist/sparkline.js +15 -0
- package/dist/sparkline.js.map +1 -0
- package/dist/svg-BJUHYX3B.js +14 -0
- package/dist/svg-BJUHYX3B.js.map +1 -0
- package/dist/treemap-OMGGGB5U.js +13 -0
- package/dist/treemap-OMGGGB5U.js.map +1 -0
- package/dist/treemap.d.ts +24 -0
- package/dist/treemap.js +14 -0
- package/dist/treemap.js.map +1 -0
- package/dist/world-110m-DVFWXS42.js +18 -0
- package/dist/world-110m-DVFWXS42.js.map +1 -0
- package/package.json +518 -3
- package/registry/area-chart.json +784 -0
- package/registry/bar-chart.json +783 -0
- package/registry/calendar-heatmap.json +459 -0
- package/registry/candlestick.json +552 -0
- package/registry/chart.json +440 -0
- package/registry/charts-provider.json +190 -0
- package/registry/examples/area-chart/credits-usage.d.ts +4 -0
- package/registry/examples/area-chart/credits-usage.js +38 -0
- package/registry/examples/area-chart/credits-usage.tsx +32 -0
- package/registry/examples/area-chart/native/credits-usage.d.ts +4 -0
- package/registry/examples/area-chart/native/credits-usage.dark.png +0 -0
- package/registry/examples/area-chart/native/credits-usage.js +33 -0
- package/registry/examples/area-chart/native/credits-usage.light.png +0 -0
- package/registry/examples/area-chart/native/credits-usage.tsx +27 -0
- package/registry/examples/area-chart/storage.d.ts +4 -0
- package/registry/examples/area-chart/storage.js +27 -0
- package/registry/examples/area-chart/storage.tsx +21 -0
- package/registry/examples/bar-chart/jobs-by-status.d.ts +4 -0
- package/registry/examples/bar-chart/jobs-by-status.js +37 -0
- package/registry/examples/bar-chart/jobs-by-status.tsx +31 -0
- package/registry/examples/bar-chart/native/jobs-by-status.d.ts +4 -0
- package/registry/examples/bar-chart/native/jobs-by-status.dark.png +0 -0
- package/registry/examples/bar-chart/native/jobs-by-status.js +32 -0
- package/registry/examples/bar-chart/native/jobs-by-status.light.png +0 -0
- package/registry/examples/bar-chart/native/jobs-by-status.tsx +26 -0
- package/registry/examples/bar-chart/plans-by-quarter.d.ts +4 -0
- package/registry/examples/bar-chart/plans-by-quarter.js +31 -0
- package/registry/examples/bar-chart/plans-by-quarter.tsx +26 -0
- package/registry/examples/bar-chart/top-supporters.d.ts +4 -0
- package/registry/examples/bar-chart/top-supporters.js +32 -0
- package/registry/examples/bar-chart/top-supporters.tsx +27 -0
- package/registry/examples/calendar-heatmap/publishing.d.ts +4 -0
- package/registry/examples/calendar-heatmap/publishing.js +28 -0
- package/registry/examples/calendar-heatmap/publishing.tsx +23 -0
- package/registry/examples/candlestick/auction-bids.d.ts +4 -0
- package/registry/examples/candlestick/auction-bids.js +37 -0
- package/registry/examples/candlestick/auction-bids.tsx +32 -0
- package/registry/examples/chart/polar-uploads.d.ts +4 -0
- package/registry/examples/chart/polar-uploads.js +34 -0
- package/registry/examples/chart/polar-uploads.tsx +30 -0
- package/registry/examples/charts-provider/french-orazaka.d.ts +4 -0
- package/registry/examples/charts-provider/french-orazaka.js +26 -0
- package/registry/examples/charts-provider/french-orazaka.tsx +22 -0
- package/registry/examples/charts-provider/native/french-orazaka.d.ts +4 -0
- package/registry/examples/charts-provider/native/french-orazaka.dark.png +0 -0
- package/registry/examples/charts-provider/native/french-orazaka.js +17 -0
- package/registry/examples/charts-provider/native/french-orazaka.light.png +0 -0
- package/registry/examples/charts-provider/native/french-orazaka.tsx +17 -0
- package/registry/examples/funnel/signup.d.ts +4 -0
- package/registry/examples/funnel/signup.js +30 -0
- package/registry/examples/funnel/signup.tsx +24 -0
- package/registry/examples/gauge/challenge-goal.d.ts +4 -0
- package/registry/examples/gauge/challenge-goal.js +24 -0
- package/registry/examples/gauge/challenge-goal.tsx +18 -0
- package/registry/examples/gauge/credits-quota.d.ts +4 -0
- package/registry/examples/gauge/credits-quota.js +26 -0
- package/registry/examples/gauge/credits-quota.tsx +19 -0
- package/registry/examples/gauge/native/credits-quota.d.ts +4 -0
- package/registry/examples/gauge/native/credits-quota.dark.png +0 -0
- package/registry/examples/gauge/native/credits-quota.js +25 -0
- package/registry/examples/gauge/native/credits-quota.light.png +0 -0
- package/registry/examples/gauge/native/credits-quota.tsx +18 -0
- package/registry/examples/geo-map/viewers.d.ts +4 -0
- package/registry/examples/geo-map/viewers.js +43 -0
- package/registry/examples/geo-map/viewers.tsx +29 -0
- package/registry/examples/globe/deployment-regions.d.ts +4 -0
- package/registry/examples/globe/deployment-regions.js +36 -0
- package/registry/examples/globe/deployment-regions.tsx +30 -0
- package/registry/examples/heatmap/upload-activity.d.ts +4 -0
- package/registry/examples/heatmap/upload-activity.js +30 -0
- package/registry/examples/heatmap/upload-activity.tsx +25 -0
- package/registry/examples/line-chart/creator-earnings.d.ts +4 -0
- package/registry/examples/line-chart/creator-earnings.js +35 -0
- package/registry/examples/line-chart/creator-earnings.tsx +30 -0
- package/registry/examples/line-chart/forecast.d.ts +4 -0
- package/registry/examples/line-chart/forecast.js +36 -0
- package/registry/examples/line-chart/forecast.tsx +30 -0
- package/registry/examples/line-chart/live-jobs.d.ts +4 -0
- package/registry/examples/line-chart/live-jobs.js +21 -0
- package/registry/examples/line-chart/live-jobs.tsx +23 -0
- package/registry/examples/line-chart/native/creator-earnings.d.ts +4 -0
- package/registry/examples/line-chart/native/creator-earnings.dark.png +0 -0
- package/registry/examples/line-chart/native/creator-earnings.js +32 -0
- package/registry/examples/line-chart/native/creator-earnings.light.png +0 -0
- package/registry/examples/line-chart/native/creator-earnings.tsx +26 -0
- package/registry/examples/line-chart/states.d.ts +4 -0
- package/registry/examples/line-chart/states.js +16 -0
- package/registry/examples/line-chart/states.tsx +13 -0
- package/registry/examples/pie-chart/credit-spend.d.ts +4 -0
- package/registry/examples/pie-chart/credit-spend.js +30 -0
- package/registry/examples/pie-chart/credit-spend.tsx +24 -0
- package/registry/examples/pie-chart/native/credit-spend.d.ts +4 -0
- package/registry/examples/pie-chart/native/credit-spend.dark.png +0 -0
- package/registry/examples/pie-chart/native/credit-spend.js +17 -0
- package/registry/examples/pie-chart/native/credit-spend.light.png +0 -0
- package/registry/examples/pie-chart/native/credit-spend.tsx +12 -0
- package/registry/examples/pie-chart/storage-by-kind.d.ts +4 -0
- package/registry/examples/pie-chart/storage-by-kind.js +31 -0
- package/registry/examples/pie-chart/storage-by-kind.tsx +26 -0
- package/registry/examples/radar-chart/model-comparison.d.ts +4 -0
- package/registry/examples/radar-chart/model-comparison.js +33 -0
- package/registry/examples/radar-chart/model-comparison.tsx +28 -0
- package/registry/examples/sankey/credit-flow.d.ts +4 -0
- package/registry/examples/sankey/credit-flow.js +37 -0
- package/registry/examples/sankey/credit-flow.tsx +32 -0
- package/registry/examples/scatter-chart/watch-time.d.ts +4 -0
- package/registry/examples/scatter-chart/watch-time.js +36 -0
- package/registry/examples/scatter-chart/watch-time.tsx +31 -0
- package/registry/examples/sparkline/bars.d.ts +4 -0
- package/registry/examples/sparkline/bars.js +12 -0
- package/registry/examples/sparkline/bars.tsx +7 -0
- package/registry/examples/sparkline/native/stat-trend.d.ts +4 -0
- package/registry/examples/sparkline/native/stat-trend.dark.png +0 -0
- package/registry/examples/sparkline/native/stat-trend.js +12 -0
- package/registry/examples/sparkline/native/stat-trend.light.png +0 -0
- package/registry/examples/sparkline/native/stat-trend.tsx +7 -0
- package/registry/examples/sparkline/stat-trend.d.ts +4 -0
- package/registry/examples/sparkline/stat-trend.js +18 -0
- package/registry/examples/sparkline/stat-trend.tsx +15 -0
- package/registry/examples/sparkline/table-rows.d.ts +4 -0
- package/registry/examples/sparkline/table-rows.js +23 -0
- package/registry/examples/sparkline/table-rows.tsx +26 -0
- package/registry/examples/treemap/storage.d.ts +4 -0
- package/registry/examples/treemap/storage.js +17 -0
- package/registry/examples/treemap/storage.tsx +13 -0
- package/registry/funnel.json +486 -0
- package/registry/gauge.json +599 -0
- package/registry/geo-map.json +483 -0
- package/registry/globe.json +468 -0
- package/registry/heatmap.json +530 -0
- package/registry/index.json +420 -0
- package/registry/line-chart.json +792 -0
- package/registry/pie-chart.json +1287 -0
- package/registry/radar-chart.json +458 -0
- package/registry/sankey.json +502 -0
- package/registry/scatter-chart.json +558 -0
- package/registry/sparkline.json +562 -0
- package/registry/treemap.json +431 -0
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
// src/core/labels.ts
|
|
4
|
+
var DEFAULT_LABELS = {
|
|
5
|
+
showData: "Show data",
|
|
6
|
+
hideData: "Hide data",
|
|
7
|
+
tableCaption: "{title} \u2014 data",
|
|
8
|
+
exportPng: "PNG",
|
|
9
|
+
exportSvg: "SVG",
|
|
10
|
+
exportCsv: "CSV",
|
|
11
|
+
loading: "Loading chart\u2026",
|
|
12
|
+
empty: "No data for this period yet.",
|
|
13
|
+
error: "The chart could not be loaded.",
|
|
14
|
+
keyboardHint: "Use the arrow keys to move between points, Home and End to jump to the ends.",
|
|
15
|
+
roleDescription: "chart",
|
|
16
|
+
summaryIntro: "{kind}, {count}.",
|
|
17
|
+
summarySeries: "{label}: from {first} to {last}",
|
|
18
|
+
summaryRange: "lowest {min} ({minAt}), highest {max} ({maxAt})",
|
|
19
|
+
summaryTrendUp: "up {change}",
|
|
20
|
+
summaryTrendDown: "down {change}",
|
|
21
|
+
summaryTrendFlat: "stable",
|
|
22
|
+
summaryTotal: "total {total}",
|
|
23
|
+
summaryThreshold: "{label} at {value}",
|
|
24
|
+
summaryShare: "{label} {value} ({share})",
|
|
25
|
+
summaryCorrelation: "correlation {r}",
|
|
26
|
+
summaryConversion: "{from} \u2192 {to} {rate}",
|
|
27
|
+
summaryOverall: "overall {rate}",
|
|
28
|
+
summaryPeak: "peak {value} ({at})",
|
|
29
|
+
summaryActive: "{count} with a value",
|
|
30
|
+
summaryOhlc: "opened at {open}, closed at {close}, low {low}, high {high}",
|
|
31
|
+
kinds: {
|
|
32
|
+
line: "Line chart",
|
|
33
|
+
area: "Area chart",
|
|
34
|
+
bar: "Bar chart",
|
|
35
|
+
pie: "Pie chart",
|
|
36
|
+
donut: "Donut chart",
|
|
37
|
+
gauge: "Gauge",
|
|
38
|
+
sparkline: "Sparkline",
|
|
39
|
+
radar: "Radar chart",
|
|
40
|
+
heatmap: "Heatmap",
|
|
41
|
+
calendar: "Calendar heatmap",
|
|
42
|
+
sankey: "Flow diagram",
|
|
43
|
+
funnel: "Funnel",
|
|
44
|
+
candlestick: "Candlestick chart",
|
|
45
|
+
treemap: "Treemap",
|
|
46
|
+
scatter: "Scatter chart",
|
|
47
|
+
map: "Map",
|
|
48
|
+
globe: "Globe",
|
|
49
|
+
chart: "Chart"
|
|
50
|
+
},
|
|
51
|
+
category: "Category",
|
|
52
|
+
value: "Value",
|
|
53
|
+
total: "Total",
|
|
54
|
+
noValue: "\u2014"
|
|
55
|
+
};
|
|
56
|
+
function mergeLabels(...layers) {
|
|
57
|
+
let out = DEFAULT_LABELS;
|
|
58
|
+
for (const layer of layers) {
|
|
59
|
+
if (!layer) continue;
|
|
60
|
+
out = { ...out, ...layer, kinds: { ...out.kinds, ...layer.kinds } };
|
|
61
|
+
}
|
|
62
|
+
return out;
|
|
63
|
+
}
|
|
64
|
+
function capitalize(text) {
|
|
65
|
+
return text.charAt(0).toLocaleUpperCase() + text.slice(1);
|
|
66
|
+
}
|
|
67
|
+
function fill(template, values) {
|
|
68
|
+
return template.replace(/\{(\w+)\}/g, (match, name) => name in values ? String(values[name]) : match);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// src/web/context.tsx
|
|
72
|
+
import { createContext, useContext, useMemo } from "react";
|
|
73
|
+
import { jsx } from "react/jsx-runtime";
|
|
74
|
+
var DEFAULTS = { locale: "en-US", labels: mergeLabels() };
|
|
75
|
+
var Context = createContext(DEFAULTS);
|
|
76
|
+
function ChartsProvider({ locale, brand, labels, children }) {
|
|
77
|
+
const parent = useContext(Context);
|
|
78
|
+
const value = useMemo(() => {
|
|
79
|
+
const raw = labels ? { ...parent.raw, ...labels, kinds: { ...parent.raw?.kinds, ...labels.kinds } } : parent.raw;
|
|
80
|
+
return { locale: locale ?? parent.locale, brand: brand ?? parent.brand, labels: mergeLabels(raw), raw };
|
|
81
|
+
}, [locale, brand, labels, parent]);
|
|
82
|
+
return /* @__PURE__ */ jsx(Context.Provider, { value, children });
|
|
83
|
+
}
|
|
84
|
+
function useChartSettings(own) {
|
|
85
|
+
const shared = useContext(Context);
|
|
86
|
+
return useMemo(
|
|
87
|
+
() => ({ locale: own.locale ?? shared.locale, brand: own.brand ?? shared.brand, labels: own.labels ? mergeLabels(shared.raw, own.labels) : shared.labels }),
|
|
88
|
+
[own.locale, own.brand, own.labels, shared]
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// src/core/palette.ts
|
|
93
|
+
var HUES = {
|
|
94
|
+
blue: { light: "#2a78d6", dark: "#3987e5" },
|
|
95
|
+
orange: { light: "#eb6834", dark: "#d95926" },
|
|
96
|
+
aqua: { light: "#1baf7a", dark: "#199e70" },
|
|
97
|
+
yellow: { light: "#eda100", dark: "#c98500" },
|
|
98
|
+
magenta: { light: "#e87ba4", dark: "#d55181" },
|
|
99
|
+
green: { light: "#008300", dark: "#008300" },
|
|
100
|
+
violet: { light: "#6250d6", dark: "#9085e9" },
|
|
101
|
+
red: { light: "#e34948", dark: "#e66767" }
|
|
102
|
+
};
|
|
103
|
+
var ORDERS = {
|
|
104
|
+
krizaka: ["blue", "green", "magenta", "yellow", "aqua", "orange", "violet", "red"],
|
|
105
|
+
orazaka: ["orange", "aqua", "blue", "yellow", "magenta", "green", "violet", "red"],
|
|
106
|
+
orochia: ["violet", "magenta", "yellow", "aqua", "orange", "blue", "green", "red"]
|
|
107
|
+
};
|
|
108
|
+
function palette(brand, mode) {
|
|
109
|
+
return ORDERS[brand].map((hue) => HUES[hue][mode]);
|
|
110
|
+
}
|
|
111
|
+
var DIVERGING = {
|
|
112
|
+
light: { low: HUES.blue.light, high: HUES.red.light },
|
|
113
|
+
dark: { low: HUES.blue.dark, high: HUES.red.dark }
|
|
114
|
+
};
|
|
115
|
+
function parseColor(color) {
|
|
116
|
+
const hex2 = color.trim().match(/^#([\da-f]{3}|[\da-f]{6})$/i);
|
|
117
|
+
if (hex2) {
|
|
118
|
+
const h = hex2[1].length === 3 ? [...hex2[1]].map((c) => c + c).join("") : hex2[1];
|
|
119
|
+
return [0, 2, 4].map((i) => Number.parseInt(h.slice(i, i + 2), 16));
|
|
120
|
+
}
|
|
121
|
+
const rgb = color.trim().match(/^rgba?\(\s*([\d.]+)[\s,]+([\d.]+)[\s,]+([\d.]+)/i);
|
|
122
|
+
if (rgb) return [Number(rgb[1]), Number(rgb[2]), Number(rgb[3])];
|
|
123
|
+
return null;
|
|
124
|
+
}
|
|
125
|
+
var toLinear = (c) => {
|
|
126
|
+
const v = c / 255;
|
|
127
|
+
return v <= 0.04045 ? v / 12.92 : ((v + 0.055) / 1.055) ** 2.4;
|
|
128
|
+
};
|
|
129
|
+
var fromLinear = (v) => {
|
|
130
|
+
const c = v <= 31308e-7 ? v * 12.92 : 1.055 * v ** (1 / 2.4) - 0.055;
|
|
131
|
+
return Math.round(Math.min(1, Math.max(0, c)) * 255);
|
|
132
|
+
};
|
|
133
|
+
function toOklab([r8, g8, b8]) {
|
|
134
|
+
const [r, g, b] = [toLinear(r8), toLinear(g8), toLinear(b8)];
|
|
135
|
+
const l = Math.cbrt(0.4122214708 * r + 0.5363325363 * g + 0.0514459929 * b);
|
|
136
|
+
const m = Math.cbrt(0.2119034982 * r + 0.6806995451 * g + 0.1073969566 * b);
|
|
137
|
+
const s = Math.cbrt(0.0883024619 * r + 0.2817188376 * g + 0.6299787005 * b);
|
|
138
|
+
return [0.2104542553 * l + 0.793617785 * m - 0.0040720468 * s, 1.9779984951 * l - 2.428592205 * m + 0.4505937099 * s, 0.0259040371 * l + 0.7827717662 * m - 0.808675766 * s];
|
|
139
|
+
}
|
|
140
|
+
function fromOklab([L, a, b]) {
|
|
141
|
+
const l = (L + 0.3963377774 * a + 0.2158037573 * b) ** 3;
|
|
142
|
+
const m = (L - 0.1055613458 * a - 0.0638541728 * b) ** 3;
|
|
143
|
+
const s = (L - 0.0894841775 * a - 1.291485548 * b) ** 3;
|
|
144
|
+
return [
|
|
145
|
+
fromLinear(4.0767416621 * l - 3.3077115913 * m + 0.2309699292 * s),
|
|
146
|
+
fromLinear(-1.2684380046 * l + 2.6097574011 * m - 0.3413193965 * s),
|
|
147
|
+
fromLinear(-0.0041960863 * l - 0.7034186147 * m + 1.707614031 * s)
|
|
148
|
+
];
|
|
149
|
+
}
|
|
150
|
+
var hex = ([r, g, b]) => `#${[r, g, b].map((c) => c.toString(16).padStart(2, "0")).join("")}`;
|
|
151
|
+
function mix(a, b, t) {
|
|
152
|
+
const ca = parseColor(a);
|
|
153
|
+
const cb = parseColor(b);
|
|
154
|
+
if (!ca || !cb) return b;
|
|
155
|
+
const la = toOklab(ca);
|
|
156
|
+
const lb = toOklab(cb);
|
|
157
|
+
return hex(fromOklab([0, 1, 2].map((i) => la[i] + (lb[i] - la[i]) * t)));
|
|
158
|
+
}
|
|
159
|
+
function sequential(hue, surface, steps = 5) {
|
|
160
|
+
return Array.from({ length: steps }, (_, i) => mix(surface, hue, 0.22 + 0.78 * i / Math.max(1, steps - 1)));
|
|
161
|
+
}
|
|
162
|
+
function contrast(a, b) {
|
|
163
|
+
const lum = (c) => {
|
|
164
|
+
const rgb = parseColor(c);
|
|
165
|
+
if (!rgb) return 0;
|
|
166
|
+
const [r, g, bl] = rgb.map(toLinear);
|
|
167
|
+
return 0.2126 * r + 0.7152 * g + 0.0722 * bl;
|
|
168
|
+
};
|
|
169
|
+
const [hi, lo] = [lum(a), lum(b)].sort((x, y) => y - x);
|
|
170
|
+
return (hi + 0.05) / (lo + 0.05);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
export {
|
|
174
|
+
DEFAULT_LABELS,
|
|
175
|
+
capitalize,
|
|
176
|
+
fill,
|
|
177
|
+
ChartsProvider,
|
|
178
|
+
useChartSettings,
|
|
179
|
+
HUES,
|
|
180
|
+
ORDERS,
|
|
181
|
+
palette,
|
|
182
|
+
DIVERGING,
|
|
183
|
+
sequential,
|
|
184
|
+
contrast
|
|
185
|
+
};
|
|
186
|
+
//# sourceMappingURL=chunk-3CJHBJXA.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/core/labels.ts","../src/web/context.tsx","../src/core/palette.ts"],"sourcesContent":["// The words a chart says on its own: its controls, its states and its written summary. English by default; an app\n// passes its own (translated through its catalogue) once, to `ChartsProvider labels`, or to one chart's `labels`.\n// Placeholders are written `{name}`.\n\nexport interface ChartLabels {\n /** The button that shows the data table. */\n showData: string;\n /** The button that hides it. */\n hideData: string;\n /** The caption of the data table: `{title}`. */\n tableCaption: string;\n /** The export buttons. */\n exportPng: string;\n exportSvg: string;\n exportCsv: string;\n /** Announced while the data loads. */\n loading: string;\n /** Shown when there is nothing to draw. */\n empty: string;\n /** Shown when the data could not be loaded. */\n error: string;\n /** The keyboard hint, read once when the plot takes the focus. */\n keyboardHint: string;\n /** The role description of the plot (`chart`). */\n roleDescription: string;\n /** Summary pieces. `{kind}` is the chart's name (`Line chart`), `{count}` a number of points or series. */\n summaryIntro: string;\n summarySeries: string;\n summaryRange: string;\n summaryTrendUp: string;\n summaryTrendDown: string;\n summaryTrendFlat: string;\n summaryTotal: string;\n summaryThreshold: string;\n summaryShare: string;\n /** Scatter: the correlation of x and y (Pearson's r). */\n summaryCorrelation: string;\n /** Funnel: from one stage to the next, and from the first to the last. */\n summaryConversion: string;\n summaryOverall: string;\n /** Heatmap, calendar: the largest cell and the number of cells with a value. */\n summaryPeak: string;\n summaryActive: string;\n /** Candlestick: the period's range. */\n summaryOhlc: string;\n /** The names of the charts, read first in the summary. */\n kinds: Record<ChartKind, string>;\n /** The column of the values, when the chart has no value label. */\n value: string;\n /** The column of the categories in the data table, when the chart has no x label. */\n category: string;\n /** The total row of a stacked chart, a pie, a funnel. */\n total: string;\n /** What a missing value reads as. */\n noValue: string;\n}\n\nexport type ChartKind =\n | \"line\"\n | \"area\"\n | \"bar\"\n | \"pie\"\n | \"donut\"\n | \"gauge\"\n | \"sparkline\"\n | \"radar\"\n | \"heatmap\"\n | \"calendar\"\n | \"sankey\"\n | \"funnel\"\n | \"candlestick\"\n | \"treemap\"\n | \"scatter\"\n | \"map\"\n | \"globe\"\n | \"chart\";\n\nexport const DEFAULT_LABELS: ChartLabels = {\n showData: \"Show data\",\n hideData: \"Hide data\",\n tableCaption: \"{title} — data\",\n exportPng: \"PNG\",\n exportSvg: \"SVG\",\n exportCsv: \"CSV\",\n loading: \"Loading chart…\",\n empty: \"No data for this period yet.\",\n error: \"The chart could not be loaded.\",\n keyboardHint: \"Use the arrow keys to move between points, Home and End to jump to the ends.\",\n roleDescription: \"chart\",\n summaryIntro: \"{kind}, {count}.\",\n summarySeries: \"{label}: from {first} to {last}\",\n summaryRange: \"lowest {min} ({minAt}), highest {max} ({maxAt})\",\n summaryTrendUp: \"up {change}\",\n summaryTrendDown: \"down {change}\",\n summaryTrendFlat: \"stable\",\n summaryTotal: \"total {total}\",\n summaryThreshold: \"{label} at {value}\",\n summaryShare: \"{label} {value} ({share})\",\n summaryCorrelation: \"correlation {r}\",\n summaryConversion: \"{from} → {to} {rate}\",\n summaryOverall: \"overall {rate}\",\n summaryPeak: \"peak {value} ({at})\",\n summaryActive: \"{count} with a value\",\n summaryOhlc: \"opened at {open}, closed at {close}, low {low}, high {high}\",\n kinds: {\n line: \"Line chart\",\n area: \"Area chart\",\n bar: \"Bar chart\",\n pie: \"Pie chart\",\n donut: \"Donut chart\",\n gauge: \"Gauge\",\n sparkline: \"Sparkline\",\n radar: \"Radar chart\",\n heatmap: \"Heatmap\",\n calendar: \"Calendar heatmap\",\n sankey: \"Flow diagram\",\n funnel: \"Funnel\",\n candlestick: \"Candlestick chart\",\n treemap: \"Treemap\",\n scatter: \"Scatter chart\",\n map: \"Map\",\n globe: \"Globe\",\n chart: \"Chart\",\n },\n category: \"Category\",\n value: \"Value\",\n total: \"Total\",\n noValue: \"—\",\n};\n\n/** The words an app or a chart passes: any of them, and any of the chart names. */\nexport type ChartLabelsInput = Partial<Omit<ChartLabels, \"kinds\">> & { kinds?: Partial<Record<ChartKind, string>> };\n\n/** The default labels with an app's and a chart's on top (`kinds` merged too). */\nexport function mergeLabels(...layers: (ChartLabelsInput | undefined)[]): ChartLabels {\n let out = DEFAULT_LABELS;\n for (const layer of layers) {\n if (!layer) continue;\n out = { ...out, ...layer, kinds: { ...out.kinds, ...layer.kinds } };\n }\n return out;\n}\n\n/** A sentence's first letter in upper case (a template that may open a sentence: `total {total}`). */\nexport function capitalize(text: string): string {\n return text.charAt(0).toLocaleUpperCase() + text.slice(1);\n}\n\n/** `{name}` → its value; an unknown placeholder stays as written. */\nexport function fill(template: string, values: Record<string, string | number>): string {\n return template.replace(/\\{(\\w+)\\}/g, (match, name: string) => (name in values ? String(values[name]) : match));\n}\n","\"use client\";\n// One place for what every chart of an app shares: the locale its figures are written in, the brand its palette\n// leads with, and the words it says (translated once, from the app's catalogue). Each chart may still override them.\nimport { createContext, type ReactNode, useContext, useMemo } from \"react\";\n\nimport { type ChartLabels, type ChartLabelsInput, mergeLabels } from \"../core/labels\";\nimport type { BrandId, Locale } from \"../core/types\";\n\nexport interface ChartsSettings {\n /** The locale of every figure and date (`\"fr-FR\"`). Default `\"en-US\"`. */\n locale?: Locale;\n /**\n * The brand whose palette the charts use. Without it, a chart follows a `.brand-<id>` ancestor, else Krizaka. Set it\n * when the app loads a brand stylesheet on `:root` (`@krizaka/tokens/brands/orazaka.css`).\n */\n brand?: BrandId;\n /** The words, translated: the buttons, the states, the written summary. */\n labels?: ChartLabelsInput;\n}\n\ninterface ResolvedSettings {\n readonly locale: Locale;\n readonly brand?: BrandId;\n readonly labels: ChartLabels;\n readonly raw?: ChartLabelsInput;\n}\n\nconst DEFAULTS: ResolvedSettings = { locale: \"en-US\", labels: mergeLabels() };\nconst Context = createContext<ResolvedSettings>(DEFAULTS);\n\nexport interface ChartsProviderProps extends ChartsSettings {\n children: ReactNode;\n}\n\n/** Sets the locale, the brand and the words of every chart below it. */\nexport function ChartsProvider({ locale, brand, labels, children }: ChartsProviderProps) {\n const parent = useContext(Context);\n const value = useMemo<ResolvedSettings>(() => {\n const raw: ChartLabelsInput | undefined = labels ? { ...parent.raw, ...labels, kinds: { ...parent.raw?.kinds, ...labels.kinds } } : parent.raw;\n return { locale: locale ?? parent.locale, brand: brand ?? parent.brand, labels: mergeLabels(raw), raw };\n }, [locale, brand, labels, parent]);\n return <Context.Provider value={value}>{children}</Context.Provider>;\n}\n\n/** The settings of a chart: its own props over the provider's over the defaults. */\nexport function useChartSettings(own: ChartsSettings): { locale: Locale; brand?: BrandId; labels: ChartLabels } {\n const shared = useContext(Context);\n return useMemo(\n () => ({ locale: own.locale ?? shared.locale, brand: own.brand ?? shared.brand, labels: own.labels ? mergeLabels(shared.raw, own.labels) : shared.labels }),\n [own.locale, own.brand, own.labels, shared],\n );\n}\n","// The data palettes. One categorical set of eight hues, stepped for each theme (the dark steps are chosen for the\n// dark surface, not flipped), ordered per brand so that the first series wears the brand's own hue — Krizaka blue,\n// Orazaka orange, Orochia violet then magenta, its gradient. Every order was chosen among the ones that pass the\n// colour-vision checks (scripts/palette.test: lightness band, chroma floor, adjacent ΔE under protan/deutan ≥ 8 —\n// Orochia light 7.2, inside the 6–8 band that requires the secondary encoding every chart carries: legend, direct\n// labels, data table —, normal-vision ΔE ≥ 15, ≥ 3:1 on the surface, the first three slots distinct all-pairs).\n// A 9th series never gets a generated hue: it folds into “Other” or a second chart.\nimport type { BrandId } from \"./types\";\n\nexport type Mode = \"dark\" | \"light\";\n\n/** The eight hues, light and dark steps. */\nexport const HUES = {\n blue: { light: \"#2a78d6\", dark: \"#3987e5\" },\n orange: { light: \"#eb6834\", dark: \"#d95926\" },\n aqua: { light: \"#1baf7a\", dark: \"#199e70\" },\n yellow: { light: \"#eda100\", dark: \"#c98500\" },\n magenta: { light: \"#e87ba4\", dark: \"#d55181\" },\n green: { light: \"#008300\", dark: \"#008300\" },\n violet: { light: \"#6250d6\", dark: \"#9085e9\" },\n red: { light: \"#e34948\", dark: \"#e66767\" },\n} as const;\n\nexport type Hue = keyof typeof HUES;\n\n/** The order of the hues for each brand: slot 1 is the brand. */\nexport const ORDERS: Record<BrandId, readonly Hue[]> = {\n krizaka: [\"blue\", \"green\", \"magenta\", \"yellow\", \"aqua\", \"orange\", \"violet\", \"red\"],\n orazaka: [\"orange\", \"aqua\", \"blue\", \"yellow\", \"magenta\", \"green\", \"violet\", \"red\"],\n orochia: [\"violet\", \"magenta\", \"yellow\", \"aqua\", \"orange\", \"blue\", \"green\", \"red\"],\n};\n\n/** The categorical palette of a brand in a theme: eight hex colours, slot 1 first. */\nexport function palette(brand: BrandId, mode: Mode): string[] {\n return ORDERS[brand].map((hue) => HUES[hue][mode]);\n}\n\n/** The diverging poles (below / above the midpoint): blue ↔ red, a neutral grey between them. */\nexport const DIVERGING = {\n light: { low: HUES.blue.light, high: HUES.red.light },\n dark: { low: HUES.blue.dark, high: HUES.red.dark },\n} as const;\n\n// --- Colour arithmetic (OKLab), for the sequential ramps the canvas engine needs as plain colours. ---------------\n\ntype Rgb = [number, number, number];\n\n/** `#rrggbb`, `#rgb`, `rgb(r, g, b)` / `rgba(…)` or `rgb(r g b / a)` → [r, g, b] in 0–255; null otherwise. */\nexport function parseColor(color: string): Rgb | null {\n const hex = color.trim().match(/^#([\\da-f]{3}|[\\da-f]{6})$/i);\n if (hex) {\n const h = hex[1]!.length === 3 ? [...hex[1]!].map((c) => c + c).join(\"\") : hex[1]!;\n return [0, 2, 4].map((i) => Number.parseInt(h.slice(i, i + 2), 16)) as Rgb;\n }\n const rgb = color.trim().match(/^rgba?\\(\\s*([\\d.]+)[\\s,]+([\\d.]+)[\\s,]+([\\d.]+)/i);\n if (rgb) return [Number(rgb[1]), Number(rgb[2]), Number(rgb[3])];\n return null;\n}\n\nconst toLinear = (c: number) => {\n const v = c / 255;\n return v <= 0.04045 ? v / 12.92 : ((v + 0.055) / 1.055) ** 2.4;\n};\nconst fromLinear = (v: number) => {\n const c = v <= 0.0031308 ? v * 12.92 : 1.055 * v ** (1 / 2.4) - 0.055;\n return Math.round(Math.min(1, Math.max(0, c)) * 255);\n};\n\nfunction toOklab([r8, g8, b8]: Rgb): Rgb {\n const [r, g, b] = [toLinear(r8), toLinear(g8), toLinear(b8)];\n const l = Math.cbrt(0.4122214708 * r + 0.5363325363 * g + 0.0514459929 * b);\n const m = Math.cbrt(0.2119034982 * r + 0.6806995451 * g + 0.1073969566 * b);\n const s = Math.cbrt(0.0883024619 * r + 0.2817188376 * g + 0.6299787005 * b);\n return [0.2104542553 * l + 0.793617785 * m - 0.0040720468 * s, 1.9779984951 * l - 2.428592205 * m + 0.4505937099 * s, 0.0259040371 * l + 0.7827717662 * m - 0.808675766 * s];\n}\n\nfunction fromOklab([L, a, b]: Rgb): Rgb {\n const l = (L + 0.3963377774 * a + 0.2158037573 * b) ** 3;\n const m = (L - 0.1055613458 * a - 0.0638541728 * b) ** 3;\n const s = (L - 0.0894841775 * a - 1.291485548 * b) ** 3;\n return [\n fromLinear(4.0767416621 * l - 3.3077115913 * m + 0.2309699292 * s),\n fromLinear(-1.2684380046 * l + 2.6097574011 * m - 0.3413193965 * s),\n fromLinear(-0.0041960863 * l - 0.7034186147 * m + 1.707614031 * s),\n ];\n}\n\nconst hex = ([r, g, b]: Rgb) => `#${[r, g, b].map((c) => c.toString(16).padStart(2, \"0\")).join(\"\")}`;\n\n/** `a` → `b` at `t` (0–1), interpolated in OKLab (even steps to the eye). Unparseable colours return `b`. */\nexport function mix(a: string, b: string, t: number): string {\n const ca = parseColor(a);\n const cb = parseColor(b);\n if (!ca || !cb) return b;\n const la = toOklab(ca);\n const lb = toOklab(cb);\n return hex(fromOklab([0, 1, 2].map((i) => la[i]! + (lb[i]! - la[i]!) * t) as Rgb));\n}\n\n/**\n * A sequential ramp of `steps` colours, one hue from near the surface (`0`, “almost nothing”) to the full hue: the\n * magnitude of a heatmap, a calendar or a choropleth. The first step is still distinct from the surface.\n */\nexport function sequential(hue: string, surface: string, steps = 5): string[] {\n return Array.from({ length: steps }, (_, i) => mix(surface, hue, 0.22 + (0.78 * i) / Math.max(1, steps - 1)));\n}\n\n/** WCAG contrast ratio between two colours (for the tests and the labels drawn inside a mark). */\nexport function contrast(a: string, b: string): number {\n const lum = (c: string) => {\n const rgb = parseColor(c);\n if (!rgb) return 0;\n const [r, g, bl] = rgb.map(toLinear) as Rgb;\n return 0.2126 * r + 0.7152 * g + 0.0722 * bl;\n };\n const [hi, lo] = [lum(a), lum(b)].sort((x, y) => y - x) as [number, number];\n return (hi + 0.05) / (lo + 0.05);\n}\n"],"mappings":"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","names":["hex"]}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
// src/geo/world.ts
|
|
4
|
+
import { useEffect, useState } from "react";
|
|
5
|
+
import { feature } from "topojson-client";
|
|
6
|
+
var world = null;
|
|
7
|
+
function loadWorld() {
|
|
8
|
+
world ??= import("./world-110m-DVFWXS42.js").then((module) => {
|
|
9
|
+
const topology = module.default ?? module;
|
|
10
|
+
return feature(topology, topology.objects.countries);
|
|
11
|
+
});
|
|
12
|
+
return world;
|
|
13
|
+
}
|
|
14
|
+
function useWorld(enabled) {
|
|
15
|
+
const [state, setState] = useState({ world: null, failed: false });
|
|
16
|
+
useEffect(() => {
|
|
17
|
+
if (!enabled) return void 0;
|
|
18
|
+
let alive = true;
|
|
19
|
+
loadWorld().then(
|
|
20
|
+
(w) => alive && setState({ world: w, failed: false }),
|
|
21
|
+
() => alive && setState({ world: null, failed: true })
|
|
22
|
+
);
|
|
23
|
+
return () => {
|
|
24
|
+
alive = false;
|
|
25
|
+
};
|
|
26
|
+
}, [enabled]);
|
|
27
|
+
return state;
|
|
28
|
+
}
|
|
29
|
+
var displayNames = /* @__PURE__ */ new Map();
|
|
30
|
+
function regionName(code, fallback, locale) {
|
|
31
|
+
if (!code) return fallback;
|
|
32
|
+
try {
|
|
33
|
+
const key = String(locale);
|
|
34
|
+
let names = displayNames.get(key);
|
|
35
|
+
if (!names) {
|
|
36
|
+
names = new Intl.DisplayNames(locale, { type: "region" });
|
|
37
|
+
displayNames.set(key, names);
|
|
38
|
+
}
|
|
39
|
+
return names.of(code) ?? fallback;
|
|
40
|
+
} catch {
|
|
41
|
+
return fallback;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export {
|
|
46
|
+
useWorld,
|
|
47
|
+
regionName
|
|
48
|
+
};
|
|
49
|
+
//# sourceMappingURL=chunk-6FINSUOS.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/geo/world.ts"],"sourcesContent":["\"use client\";\n// The world the maps draw: Natural Earth 1:110m countries (public domain) through world-atlas, keyed by ISO 3166-1\n// alpha-2 (scripts/world.mjs). ~38 kB gzipped, loaded on demand — only by GeoMap and Globe3D, once per page.\nimport type { Feature, FeatureCollection, Geometry } from \"geojson\";\nimport { useEffect, useState } from \"react\";\nimport { feature } from \"topojson-client\";\nimport type { GeometryCollection, Topology } from \"topojson-specification\";\n\nexport type Country = Omit<Feature<Geometry, { name: string }>, \"id\"> & { id?: string };\nexport type World = Omit<FeatureCollection<Geometry, { name: string }>, \"features\"> & { features: Country[] };\n\nlet world: Promise<World> | null = null;\n\n/** The countries, decoded once (a lazy chunk of the package). */\nexport function loadWorld(): Promise<World> {\n world ??= import(\"./world-110m.json\").then((module) => {\n const topology = (module.default ?? module) as unknown as Topology<{ countries: GeometryCollection<{ name: string }> }>;\n return feature(topology, topology.objects.countries) as unknown as World;\n });\n return world;\n}\n\n/** The world once loaded (null before, or when `enabled` is false); an error leaves it null and says so. */\nexport function useWorld(enabled: boolean): { world: World | null; failed: boolean } {\n const [state, setState] = useState<{ world: World | null; failed: boolean }>({ world: null, failed: false });\n useEffect(() => {\n if (!enabled) return undefined;\n let alive = true;\n loadWorld().then(\n (w) => alive && setState({ world: w, failed: false }),\n () => alive && setState({ world: null, failed: true }),\n );\n return () => {\n alive = false;\n };\n }, [enabled]);\n return state;\n}\n\nconst displayNames = new Map<string, Intl.DisplayNames>();\n\n/** A region's name in the reader's language (`Intl.DisplayNames`), else Natural Earth's English one. */\nexport function regionName(code: string | undefined, fallback: string, locale: string | readonly string[]): string {\n if (!code) return fallback;\n try {\n const key = String(locale);\n let names = displayNames.get(key);\n if (!names) {\n names = new Intl.DisplayNames(locale as string[], { type: \"region\" });\n displayNames.set(key, names);\n }\n return names.of(code) ?? fallback;\n } catch {\n return fallback;\n }\n}\n"],"mappings":";;;AAIA,SAAS,WAAW,gBAAgB;AACpC,SAAS,eAAe;AAMxB,IAAI,QAA+B;AAG5B,SAAS,YAA4B;AAC1C,YAAU,OAAO,0BAAmB,EAAE,KAAK,CAAC,WAAW;AACrD,UAAM,WAAY,OAAO,WAAW;AACpC,WAAO,QAAQ,UAAU,SAAS,QAAQ,SAAS;AAAA,EACrD,CAAC;AACD,SAAO;AACT;AAGO,SAAS,SAAS,SAA4D;AACnF,QAAM,CAAC,OAAO,QAAQ,IAAI,SAAmD,EAAE,OAAO,MAAM,QAAQ,MAAM,CAAC;AAC3G,YAAU,MAAM;AACd,QAAI,CAAC,QAAS,QAAO;AACrB,QAAI,QAAQ;AACZ,cAAU,EAAE;AAAA,MACV,CAAC,MAAM,SAAS,SAAS,EAAE,OAAO,GAAG,QAAQ,MAAM,CAAC;AAAA,MACpD,MAAM,SAAS,SAAS,EAAE,OAAO,MAAM,QAAQ,KAAK,CAAC;AAAA,IACvD;AACA,WAAO,MAAM;AACX,cAAQ;AAAA,IACV;AAAA,EACF,GAAG,CAAC,OAAO,CAAC;AACZ,SAAO;AACT;AAEA,IAAM,eAAe,oBAAI,IAA+B;AAGjD,SAAS,WAAW,MAA0B,UAAkB,QAA4C;AACjH,MAAI,CAAC,KAAM,QAAO;AAClB,MAAI;AACF,UAAM,MAAM,OAAO,MAAM;AACzB,QAAI,QAAQ,aAAa,IAAI,GAAG;AAChC,QAAI,CAAC,OAAO;AACV,cAAQ,IAAI,KAAK,aAAa,QAAoB,EAAE,MAAM,SAAS,CAAC;AACpE,mBAAa,IAAI,KAAK,KAAK;AAAA,IAC7B;AACA,WAAO,MAAM,GAAG,IAAI,KAAK;AAAA,EAC3B,QAAQ;AACN,WAAO;AAAA,EACT;AACF;","names":[]}
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import {
|
|
3
|
+
EChartHost,
|
|
4
|
+
baseOption,
|
|
5
|
+
categoryAxis,
|
|
6
|
+
tooltipHtml
|
|
7
|
+
} from "./chunk-I5QUZVU2.js";
|
|
8
|
+
import {
|
|
9
|
+
read
|
|
10
|
+
} from "./chunk-W5FX4TU3.js";
|
|
11
|
+
import {
|
|
12
|
+
asDate,
|
|
13
|
+
categoryFormatter,
|
|
14
|
+
valueFormatter
|
|
15
|
+
} from "./chunk-XLLYNNC6.js";
|
|
16
|
+
import {
|
|
17
|
+
RampLegend,
|
|
18
|
+
useSettings
|
|
19
|
+
} from "./chunk-DWJPPEMC.js";
|
|
20
|
+
import {
|
|
21
|
+
capitalize,
|
|
22
|
+
fill
|
|
23
|
+
} from "./chunk-3CJHBJXA.js";
|
|
24
|
+
|
|
25
|
+
// src/heatmap/heatmap.tsx
|
|
26
|
+
import { useCallback, useMemo } from "react";
|
|
27
|
+
import { jsx } from "react/jsx-runtime";
|
|
28
|
+
var engine = () => import("./heatmap-JWQOKUGM.js");
|
|
29
|
+
var STEPS = 5;
|
|
30
|
+
var pieces = (theme, min, max) => theme.ramp.map((color, i) => ({ gte: min + (max - min) * i / STEPS, ...i < STEPS - 1 ? { lt: min + (max - min) * (i + 1) / STEPS } : {}, color }));
|
|
31
|
+
function Heatmap(props) {
|
|
32
|
+
const { data, x, y, value, xCategories, yCategories, format, xFormat, yFormat, xLabel, yLabel } = props;
|
|
33
|
+
const { locale, labels } = useSettings(props);
|
|
34
|
+
const fmt = useMemo(
|
|
35
|
+
() => ({ value: valueFormatter(format, locale, labels.noValue), axis: valueFormatter(format, locale, labels.noValue, true), x: categoryFormatter(xFormat ?? "text", locale), y: categoryFormatter(yFormat ?? "text", locale) }),
|
|
36
|
+
[format, xFormat, yFormat, locale, labels.noValue]
|
|
37
|
+
);
|
|
38
|
+
const model = useMemo(() => {
|
|
39
|
+
const xs = xCategories ? [...xCategories] : [...new Set(data.map((d, i) => read(x, d, i)))];
|
|
40
|
+
const ys = yCategories ? [...yCategories] : [...new Set(data.map((d, i) => read(y, d, i)))];
|
|
41
|
+
const cells = data.map((d, i) => ({ xi: xs.findIndex((c) => String(c) === String(read(x, d, i))), yi: ys.findIndex((c) => String(c) === String(read(y, d, i))), v: Number(read(value, d, i)) })).filter((c) => c.xi >= 0 && c.yi >= 0 && Number.isFinite(c.v));
|
|
42
|
+
const values = cells.map((c) => c.v);
|
|
43
|
+
return { xs: xs.map(fmt.x), ys: ys.map(fmt.y), cells, min: Math.min(...values, 0), max: Math.max(...values, 0) };
|
|
44
|
+
}, [data, x, y, value, xCategories, yCategories, fmt]);
|
|
45
|
+
const isEmpty = model.cells.length === 0;
|
|
46
|
+
const peak = model.cells.reduce((best, c) => !best || c.v > best.v ? c : best, null);
|
|
47
|
+
const summary = isEmpty ? labels.empty : `${fill(labels.summaryIntro, { kind: labels.kinds.heatmap, count: `${model.xs.length} \xD7 ${model.ys.length}` })} ${capitalize(fill(labels.summaryPeak, { value: fmt.value(peak.v), at: `${model.ys[peak.yi]}, ${model.xs[peak.xi]}` }))}, ${fill(labels.summaryActive, { count: model.cells.filter((c) => c.v !== 0).length })}.`;
|
|
48
|
+
const items = model.cells.map((c, i) => ({ seriesIndex: 0, dataIndex: i, text: `${model.ys[c.yi]}, ${model.xs[c.xi]}: ${fmt.value(c.v)}` }));
|
|
49
|
+
const build = useCallback(
|
|
50
|
+
(theme, size) => {
|
|
51
|
+
const base = baseOption(theme, true);
|
|
52
|
+
return {
|
|
53
|
+
...base,
|
|
54
|
+
tooltip: {
|
|
55
|
+
...base.tooltip,
|
|
56
|
+
trigger: "item",
|
|
57
|
+
formatter: (p) => {
|
|
58
|
+
const c = model.cells[p.dataIndex];
|
|
59
|
+
return tooltipHtml(`${model.ys[c.yi]} \xB7 ${model.xs[c.xi]}`, [{ label: labels.value, value: fmt.value(c.v) }]);
|
|
60
|
+
}
|
|
61
|
+
},
|
|
62
|
+
grid: { left: 8, right: 8, top: 8, bottom: 8, containLabel: true },
|
|
63
|
+
xAxis: { ...categoryAxis(theme, model.xs), axisLine: { show: false }, axisLabel: { color: theme.text2, interval: size.width < 480 ? "auto" : 0 } },
|
|
64
|
+
yAxis: { ...categoryAxis(theme, model.ys), axisLine: { show: false }, inverse: true },
|
|
65
|
+
visualMap: { show: false, type: "piecewise", pieces: pieces(theme, model.min, model.max), dimension: 2 },
|
|
66
|
+
series: [
|
|
67
|
+
{
|
|
68
|
+
type: "heatmap",
|
|
69
|
+
data: model.cells.map((c) => [c.xi, c.yi, c.v]),
|
|
70
|
+
itemStyle: { borderColor: theme.surface, borderWidth: 2, borderRadius: 3 },
|
|
71
|
+
emphasis: { itemStyle: { borderColor: theme.text, borderWidth: 2 } }
|
|
72
|
+
}
|
|
73
|
+
]
|
|
74
|
+
};
|
|
75
|
+
},
|
|
76
|
+
[model, fmt, labels.value]
|
|
77
|
+
);
|
|
78
|
+
return /* @__PURE__ */ jsx(
|
|
79
|
+
EChartHost,
|
|
80
|
+
{
|
|
81
|
+
kind: "heatmap",
|
|
82
|
+
frame: props,
|
|
83
|
+
defaultHeight: 260,
|
|
84
|
+
table: { columns: [yLabel && xLabel ? `${yLabel} / ${xLabel}` : yLabel ?? labels.category, ...model.xs], rows: model.ys.map((row, yi) => [row, ...model.xs.map((_, xi) => fmt.value(model.cells.find((c) => c.xi === xi && c.yi === yi)?.v))]) },
|
|
85
|
+
summary,
|
|
86
|
+
isEmpty,
|
|
87
|
+
legend: isEmpty ? null : /* @__PURE__ */ jsx(RampLegend, { min: model.min, max: model.max, steps: STEPS, write: fmt.axis }),
|
|
88
|
+
engine,
|
|
89
|
+
build,
|
|
90
|
+
items
|
|
91
|
+
}
|
|
92
|
+
);
|
|
93
|
+
}
|
|
94
|
+
var iso = (date) => date.toISOString().slice(0, 10);
|
|
95
|
+
function CalendarHeatmap(props) {
|
|
96
|
+
const { data, date, value, range, format, valueLabel } = props;
|
|
97
|
+
const { locale, labels } = useSettings(props);
|
|
98
|
+
const fmt = useMemo(() => ({ value: valueFormatter(format, locale, labels.noValue), axis: valueFormatter(format, locale, labels.noValue, true), day: categoryFormatter("date", locale) }), [format, locale, labels.noValue]);
|
|
99
|
+
const model = useMemo(() => {
|
|
100
|
+
const days = data.map((d, i) => ({ day: asDate(read(date, d, i)), v: Number(read(value, d, i)) })).filter((d) => d.day !== null && Number.isFinite(d.v)).map((d) => ({ day: iso(d.day), v: d.v })).sort((a, b) => a.day.localeCompare(b.day));
|
|
101
|
+
const last = days[days.length - 1]?.day ?? iso(/* @__PURE__ */ new Date(0));
|
|
102
|
+
const first = /* @__PURE__ */ new Date(`${last}T00:00:00Z`);
|
|
103
|
+
first.setUTCDate(first.getUTCDate() - 364);
|
|
104
|
+
const span = range ?? [iso(first), last];
|
|
105
|
+
const values = days.map((d) => d.v);
|
|
106
|
+
return { days, span, min: Math.min(...values, 0), max: Math.max(...values, 0) };
|
|
107
|
+
}, [data, date, value, range]);
|
|
108
|
+
const isEmpty = model.days.length === 0;
|
|
109
|
+
const peak = model.days.reduce((best, d) => !best || d.v > best.v ? d : best, null);
|
|
110
|
+
const total = model.days.reduce((sum, d) => sum + d.v, 0);
|
|
111
|
+
const summary = isEmpty ? labels.empty : `${fill(labels.summaryIntro, { kind: labels.kinds.calendar, count: `${fmt.day(model.span[0])} \u2013 ${fmt.day(model.span[1])}` })} ${capitalize(fill(labels.summaryTotal, { total: fmt.value(total) }))}, ${fill(labels.summaryPeak, { value: fmt.value(peak.v), at: fmt.day(peak.day) })}, ${fill(labels.summaryActive, { count: model.days.filter((d) => d.v !== 0).length })}.`;
|
|
112
|
+
const items = model.days.map((d, i) => ({ seriesIndex: 0, dataIndex: i, text: `${fmt.day(d.day)}: ${fmt.value(d.v)}` }));
|
|
113
|
+
const build = useCallback(
|
|
114
|
+
(theme, size) => {
|
|
115
|
+
const base = baseOption(theme, true);
|
|
116
|
+
const cell = Math.max(6, Math.min(18, Math.floor((size.width - 48) / 54)));
|
|
117
|
+
const monthNames = Array.from({ length: 12 }, (_, m) => new Intl.DateTimeFormat(locale, { month: "short", timeZone: "UTC" }).format(new Date(Date.UTC(2026, m, 1))));
|
|
118
|
+
const dayNames = Array.from({ length: 7 }, (_, d) => new Intl.DateTimeFormat(locale, { weekday: "narrow", timeZone: "UTC" }).format(new Date(Date.UTC(2026, 2, 1 + d))));
|
|
119
|
+
return {
|
|
120
|
+
...base,
|
|
121
|
+
tooltip: {
|
|
122
|
+
...base.tooltip,
|
|
123
|
+
trigger: "item",
|
|
124
|
+
formatter: (p) => tooltipHtml(fmt.day(p.data[0]), [{ label: valueLabel ?? labels.value, value: fmt.value(p.data[1]) }])
|
|
125
|
+
},
|
|
126
|
+
visualMap: { show: false, type: "piecewise", pieces: pieces(theme, model.min, model.max) },
|
|
127
|
+
calendar: {
|
|
128
|
+
range: [...model.span],
|
|
129
|
+
cellSize: [cell, cell],
|
|
130
|
+
top: 24,
|
|
131
|
+
left: 32,
|
|
132
|
+
right: 8,
|
|
133
|
+
orient: "horizontal",
|
|
134
|
+
splitLine: { show: false },
|
|
135
|
+
itemStyle: { color: theme.surface2, borderColor: theme.surface, borderWidth: 2 },
|
|
136
|
+
yearLabel: { show: false },
|
|
137
|
+
monthLabel: { color: theme.text2, nameMap: monthNames, fontSize: 11 },
|
|
138
|
+
dayLabel: { color: theme.text3, nameMap: dayNames, firstDay: 1, fontSize: 10 }
|
|
139
|
+
},
|
|
140
|
+
series: [{ type: "heatmap", coordinateSystem: "calendar", data: model.days.map((d) => [d.day, d.v]), itemStyle: { borderColor: theme.surface, borderWidth: 2, borderRadius: 2 } }]
|
|
141
|
+
};
|
|
142
|
+
},
|
|
143
|
+
[model, fmt, valueLabel, locale, labels.value]
|
|
144
|
+
);
|
|
145
|
+
return /* @__PURE__ */ jsx(
|
|
146
|
+
EChartHost,
|
|
147
|
+
{
|
|
148
|
+
kind: "calendar",
|
|
149
|
+
frame: props,
|
|
150
|
+
defaultHeight: 170,
|
|
151
|
+
table: { columns: [labels.category, valueLabel ?? labels.value], rows: model.days.map((d) => [fmt.day(d.day), fmt.value(d.v)]) },
|
|
152
|
+
summary,
|
|
153
|
+
isEmpty,
|
|
154
|
+
legend: isEmpty ? null : /* @__PURE__ */ jsx(RampLegend, { min: model.min, max: model.max, steps: STEPS, write: fmt.axis }),
|
|
155
|
+
engine,
|
|
156
|
+
build,
|
|
157
|
+
items
|
|
158
|
+
}
|
|
159
|
+
);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
export {
|
|
163
|
+
Heatmap,
|
|
164
|
+
CalendarHeatmap
|
|
165
|
+
};
|
|
166
|
+
//# sourceMappingURL=chunk-7CSAGFBW.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/heatmap/heatmap.tsx"],"sourcesContent":["\"use client\";\n// Magnitude across two dimensions — activity by weekday and hour — and its calendar form, one cell a day over a year.\n// One sequential hue (the brand's) in even steps from near the surface; the legend writes each step's range; the\n// keyboard walks the cells that have a value. ECharts, loaded when the chart nears the screen.\nimport { useCallback, useMemo } from \"react\";\n\nimport { read } from \"../core/data\";\nimport { asDate, categoryFormatter, valueFormatter } from \"../core/format\";\nimport { capitalize, fill } from \"../core/labels\";\nimport type { Accessor, CategoryFormat, Datum, ValueFormat } from \"../core/types\";\nimport { EChartHost, type EngineProps, type WalkItem } from \"../echarts/host\";\nimport { baseOption, categoryAxis, type ResolvedTheme, tooltipHtml } from \"../echarts/theme\";\nimport type { ChartFrameProps } from \"../web/frame\";\nimport { useSettings } from \"../web/frame\";\nimport { RampLegend } from \"../web/parts\";\n\nconst engine = () => import(\"../echarts/engines/heatmap\");\nconst STEPS = 5;\n\nconst pieces = (theme: ResolvedTheme, min: number, max: number) =>\n theme.ramp.map((color, i) => ({ gte: min + ((max - min) * i) / STEPS, ...(i < STEPS - 1 ? { lt: min + ((max - min) * (i + 1)) / STEPS } : {}), color }));\n\nexport interface HeatmapProps<T extends Datum> extends ChartFrameProps, EngineProps {\n /** One row per cell. */\n data: readonly T[];\n /** The field of the column (an hour, a day) and of the row (a weekday, a team). */\n x: Accessor<T, unknown>;\n/** The field of the row (a weekday, a team). */\n y: Accessor<T, unknown>;\n /** The field of the cell's value. */\n value: Accessor<T, number>;\n /** The order of the columns and the rows. Default: as they first appear. */\n xCategories?: readonly unknown[];\n/** The order of the rows. Default: as they first appear. */\n yCategories?: readonly unknown[];\n /** How the values, the columns and the rows are written. */\n format?: ValueFormat;\n/** How the columns are written. */\n xFormat?: CategoryFormat;\n/** How the rows are written. */\n yFormat?: CategoryFormat;\n /** The headers of the data table. */\n xLabel?: string;\n/** The header of the rows in the data table. */\n yLabel?: string;\n}\n\nexport function Heatmap<T extends Datum>(props: HeatmapProps<T>) {\n const { data, x, y, value, xCategories, yCategories, format, xFormat, yFormat, xLabel, yLabel } = props;\n const { locale, labels } = useSettings(props);\n const fmt = useMemo(\n () => ({ value: valueFormatter(format, locale, labels.noValue), axis: valueFormatter(format, locale, labels.noValue, true), x: categoryFormatter(xFormat ?? \"text\", locale), y: categoryFormatter(yFormat ?? \"text\", locale) }),\n [format, xFormat, yFormat, locale, labels.noValue],\n );\n const model = useMemo(() => {\n const xs = xCategories ? [...xCategories] : [...new Set(data.map((d, i) => read(x, d, i)))];\n const ys = yCategories ? [...yCategories] : [...new Set(data.map((d, i) => read(y, d, i)))];\n const cells = data\n .map((d, i) => ({ xi: xs.findIndex((c) => String(c) === String(read(x, d, i))), yi: ys.findIndex((c) => String(c) === String(read(y, d, i))), v: Number(read(value, d, i)) }))\n .filter((c) => c.xi >= 0 && c.yi >= 0 && Number.isFinite(c.v));\n const values = cells.map((c) => c.v);\n return { xs: xs.map(fmt.x), ys: ys.map(fmt.y), cells, min: Math.min(...values, 0), max: Math.max(...values, 0) };\n }, [data, x, y, value, xCategories, yCategories, fmt]);\n const isEmpty = model.cells.length === 0;\n const peak = model.cells.reduce<(typeof model.cells)[number] | null>((best, c) => (!best || c.v > best.v ? c : best), null);\n const summary = isEmpty\n ? labels.empty\n : `${fill(labels.summaryIntro, { kind: labels.kinds.heatmap, count: `${model.xs.length} × ${model.ys.length}` })} ${capitalize(fill(labels.summaryPeak, { value: fmt.value(peak!.v), at: `${model.ys[peak!.yi]}, ${model.xs[peak!.xi]}` }))}, ${fill(labels.summaryActive, { count: model.cells.filter((c) => c.v !== 0).length })}.`;\n const items: WalkItem[] = model.cells.map((c, i) => ({ seriesIndex: 0, dataIndex: i, text: `${model.ys[c.yi]}, ${model.xs[c.xi]}: ${fmt.value(c.v)}` }));\n\n const build = useCallback(\n (theme: ResolvedTheme, size: { width: number }) => {\n const base = baseOption(theme, true);\n return {\n ...base,\n tooltip: {\n ...(base.tooltip as object),\n trigger: \"item\",\n formatter: (p: { dataIndex: number }) => {\n const c = model.cells[p.dataIndex]!;\n return tooltipHtml(`${model.ys[c.yi]} · ${model.xs[c.xi]}`, [{ label: labels.value, value: fmt.value(c.v) }]);\n },\n },\n grid: { left: 8, right: 8, top: 8, bottom: 8, containLabel: true },\n xAxis: { ...categoryAxis(theme, model.xs), axisLine: { show: false }, axisLabel: { color: theme.text2, interval: size.width < 480 ? \"auto\" : 0 } },\n yAxis: { ...categoryAxis(theme, model.ys), axisLine: { show: false }, inverse: true },\n visualMap: { show: false, type: \"piecewise\", pieces: pieces(theme, model.min, model.max), dimension: 2 },\n series: [\n {\n type: \"heatmap\",\n data: model.cells.map((c) => [c.xi, c.yi, c.v]),\n itemStyle: { borderColor: theme.surface, borderWidth: 2, borderRadius: 3 },\n emphasis: { itemStyle: { borderColor: theme.text, borderWidth: 2 } },\n },\n ],\n };\n },\n [model, fmt, labels.value],\n );\n\n return (\n <EChartHost\n kind=\"heatmap\"\n frame={props}\n defaultHeight={260}\n table={{ columns: [yLabel && xLabel ? `${yLabel} / ${xLabel}` : (yLabel ?? labels.category), ...model.xs], rows: model.ys.map((row, yi) => [row, ...model.xs.map((_, xi) => fmt.value(model.cells.find((c) => c.xi === xi && c.yi === yi)?.v))]) }}\n summary={summary}\n isEmpty={isEmpty}\n legend={isEmpty ? null : <RampLegend min={model.min} max={model.max} steps={STEPS} write={fmt.axis} />}\n engine={engine}\n build={build}\n items={items}\n />\n );\n}\n\nexport interface CalendarHeatmapProps<T extends Datum> extends ChartFrameProps, EngineProps {\n /** One row per day (days without a row read as nothing). */\n data: readonly T[];\n /** The field of the day: an ISO date (`2026-04-12`), a `Date` or an epoch. */\n date: Accessor<T, unknown>;\n /** The field of the day's value. */\n value: Accessor<T, number>;\n /** The first and last days shown. Default: the year before the last day of the data. */\n range?: readonly [string, string];\n /** How the values are written. */\n format?: ValueFormat;\n /** The header of the values in the data table. */\n valueLabel?: string;\n}\n\nconst iso = (date: Date) => date.toISOString().slice(0, 10);\n\nexport function CalendarHeatmap<T extends Datum>(props: CalendarHeatmapProps<T>) {\n const { data, date, value, range, format, valueLabel } = props;\n const { locale, labels } = useSettings(props);\n const fmt = useMemo(() => ({ value: valueFormatter(format, locale, labels.noValue), axis: valueFormatter(format, locale, labels.noValue, true), day: categoryFormatter(\"date\", locale) }), [format, locale, labels.noValue]);\n const model = useMemo(() => {\n const days = data\n .map((d, i) => ({ day: asDate(read(date, d, i)), v: Number(read(value, d, i)) }))\n .filter((d): d is { day: Date; v: number } => d.day !== null && Number.isFinite(d.v))\n .map((d) => ({ day: iso(d.day), v: d.v }))\n .sort((a, b) => a.day.localeCompare(b.day));\n const last = days[days.length - 1]?.day ?? iso(new Date(0));\n const first = new Date(`${last}T00:00:00Z`);\n first.setUTCDate(first.getUTCDate() - 364);\n const span = range ?? ([iso(first), last] as const);\n const values = days.map((d) => d.v);\n return { days, span, min: Math.min(...values, 0), max: Math.max(...values, 0) };\n }, [data, date, value, range]);\n const isEmpty = model.days.length === 0;\n const peak = model.days.reduce<(typeof model.days)[number] | null>((best, d) => (!best || d.v > best.v ? d : best), null);\n const total = model.days.reduce((sum, d) => sum + d.v, 0);\n const summary = isEmpty\n ? labels.empty\n : `${fill(labels.summaryIntro, { kind: labels.kinds.calendar, count: `${fmt.day(model.span[0])} – ${fmt.day(model.span[1])}` })} ${capitalize(fill(labels.summaryTotal, { total: fmt.value(total) }))}, ${fill(labels.summaryPeak, { value: fmt.value(peak!.v), at: fmt.day(peak!.day) })}, ${fill(labels.summaryActive, { count: model.days.filter((d) => d.v !== 0).length })}.`;\n const items: WalkItem[] = model.days.map((d, i) => ({ seriesIndex: 0, dataIndex: i, text: `${fmt.day(d.day)}: ${fmt.value(d.v)}` }));\n\n const build = useCallback(\n (theme: ResolvedTheme, size: { width: number; height: number }) => {\n const base = baseOption(theme, true);\n const cell = Math.max(6, Math.min(18, Math.floor((size.width - 48) / 54)));\n const monthNames = Array.from({ length: 12 }, (_, m) => new Intl.DateTimeFormat(locale as string, { month: \"short\", timeZone: \"UTC\" }).format(new Date(Date.UTC(2026, m, 1))));\n const dayNames = Array.from({ length: 7 }, (_, d) => new Intl.DateTimeFormat(locale as string, { weekday: \"narrow\", timeZone: \"UTC\" }).format(new Date(Date.UTC(2026, 2, 1 + d))));\n return {\n ...base,\n tooltip: {\n ...(base.tooltip as object),\n trigger: \"item\",\n formatter: (p: { data: [string, number] }) => tooltipHtml(fmt.day(p.data[0]), [{ label: valueLabel ?? labels.value, value: fmt.value(p.data[1]) }]),\n },\n visualMap: { show: false, type: \"piecewise\", pieces: pieces(theme, model.min, model.max) },\n calendar: {\n range: [...model.span],\n cellSize: [cell, cell],\n top: 24,\n left: 32,\n right: 8,\n orient: \"horizontal\",\n splitLine: { show: false },\n itemStyle: { color: theme.surface2, borderColor: theme.surface, borderWidth: 2 },\n yearLabel: { show: false },\n monthLabel: { color: theme.text2, nameMap: monthNames, fontSize: 11 },\n dayLabel: { color: theme.text3, nameMap: dayNames, firstDay: 1, fontSize: 10 },\n },\n series: [{ type: \"heatmap\", coordinateSystem: \"calendar\", data: model.days.map((d) => [d.day, d.v]), itemStyle: { borderColor: theme.surface, borderWidth: 2, borderRadius: 2 } }],\n };\n },\n [model, fmt, valueLabel, locale, labels.value],\n );\n\n return (\n <EChartHost\n kind=\"calendar\"\n frame={props}\n defaultHeight={170}\n table={{ columns: [labels.category, valueLabel ?? labels.value], rows: model.days.map((d) => [fmt.day(d.day), fmt.value(d.v)]) }}\n summary={summary}\n isEmpty={isEmpty}\n legend={isEmpty ? null : <RampLegend min={model.min} max={model.max} steps={STEPS} write={fmt.axis} />}\n engine={engine}\n build={build}\n items={items}\n />\n );\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import {
|
|
3
|
+
EChartHost,
|
|
4
|
+
baseOption,
|
|
5
|
+
tooltipHtml
|
|
6
|
+
} from "./chunk-I5QUZVU2.js";
|
|
7
|
+
import {
|
|
8
|
+
normalizeSeries,
|
|
9
|
+
summarize,
|
|
10
|
+
tabulate
|
|
11
|
+
} from "./chunk-W5FX4TU3.js";
|
|
12
|
+
import {
|
|
13
|
+
categoryFormatter,
|
|
14
|
+
valueFormatter
|
|
15
|
+
} from "./chunk-XLLYNNC6.js";
|
|
16
|
+
import {
|
|
17
|
+
Legend,
|
|
18
|
+
useSettings
|
|
19
|
+
} from "./chunk-DWJPPEMC.js";
|
|
20
|
+
import {
|
|
21
|
+
fill
|
|
22
|
+
} from "./chunk-3CJHBJXA.js";
|
|
23
|
+
|
|
24
|
+
// src/radar/radar-chart.tsx
|
|
25
|
+
import { useCallback, useMemo } from "react";
|
|
26
|
+
import { jsx } from "react/jsx-runtime";
|
|
27
|
+
var engine = () => import("./radar-75GRJ2IK.js");
|
|
28
|
+
function RadarChart(props) {
|
|
29
|
+
const { data, x, series, format, max, xLabel } = props;
|
|
30
|
+
const { locale, labels } = useSettings(props);
|
|
31
|
+
const specs = useMemo(() => normalizeSeries(series, void 0, void 0), [series]);
|
|
32
|
+
const table = useMemo(() => tabulate(data, x, specs), [data, x, specs]);
|
|
33
|
+
const value = useMemo(() => valueFormatter(format, locale, labels.noValue), [format, locale, labels.noValue]);
|
|
34
|
+
const axisNames = useMemo(() => table.categories.map((c) => categoryFormatter("text", locale)(c)), [table, locale]);
|
|
35
|
+
const isEmpty = !data.length || !specs.length;
|
|
36
|
+
const top = max ?? Math.max(1, ...table.series.flatMap((s) => s.values.map((v) => v ?? 0))) * 1.1;
|
|
37
|
+
const summary = isEmpty ? labels.empty : [
|
|
38
|
+
fill(labels.summaryIntro, { kind: labels.kinds.radar, count: `${specs.length} \xD7 ${data.length}` }),
|
|
39
|
+
...table.series.map((s) => {
|
|
40
|
+
const sum = summarize(s, axisNames, String);
|
|
41
|
+
return `${s.label}: ${fill(labels.summaryRange, { min: value(sum.min?.value), minAt: sum.min?.category ?? "", max: value(sum.max?.value), maxAt: sum.max?.category ?? "" })}.`;
|
|
42
|
+
})
|
|
43
|
+
].join(" ");
|
|
44
|
+
const items = table.series.map((s, k) => ({ seriesIndex: 0, dataIndex: k, text: `${s.label}: ${axisNames.map((a, i) => `${a} ${value(s.values[i])}`).join(", ")}` }));
|
|
45
|
+
const build = useCallback(
|
|
46
|
+
(theme) => ({
|
|
47
|
+
...baseOption(theme, true),
|
|
48
|
+
tooltip: {
|
|
49
|
+
...baseOption(theme, true).tooltip,
|
|
50
|
+
trigger: "item",
|
|
51
|
+
formatter: (p) => {
|
|
52
|
+
const s = table.series[p.dataIndex];
|
|
53
|
+
return tooltipHtml(s.label, axisNames.map((a, i) => ({ label: a, value: value(s.values[i]) })));
|
|
54
|
+
}
|
|
55
|
+
},
|
|
56
|
+
radar: {
|
|
57
|
+
indicator: axisNames.map((name) => ({ name, max: top })),
|
|
58
|
+
radius: "68%",
|
|
59
|
+
splitNumber: 4,
|
|
60
|
+
axisName: { color: theme.text2, fontSize: 11 },
|
|
61
|
+
splitLine: { lineStyle: { color: theme.grid } },
|
|
62
|
+
splitArea: { show: false },
|
|
63
|
+
axisLine: { lineStyle: { color: theme.grid } }
|
|
64
|
+
},
|
|
65
|
+
series: [
|
|
66
|
+
{
|
|
67
|
+
type: "radar",
|
|
68
|
+
symbol: "circle",
|
|
69
|
+
symbolSize: 6,
|
|
70
|
+
data: table.series.map((s, k) => ({
|
|
71
|
+
name: s.label,
|
|
72
|
+
value: s.values.map((v) => v ?? 0),
|
|
73
|
+
lineStyle: { width: 2, color: theme.palette[k % 8] },
|
|
74
|
+
itemStyle: { color: theme.palette[k % 8], borderColor: theme.surface, borderWidth: 2 },
|
|
75
|
+
areaStyle: { color: theme.palette[k % 8], opacity: 0.12 }
|
|
76
|
+
})),
|
|
77
|
+
emphasis: { lineStyle: { width: 3 }, areaStyle: { opacity: 0.25 } }
|
|
78
|
+
}
|
|
79
|
+
]
|
|
80
|
+
}),
|
|
81
|
+
[table, axisNames, value, top]
|
|
82
|
+
);
|
|
83
|
+
return /* @__PURE__ */ jsx(
|
|
84
|
+
EChartHost,
|
|
85
|
+
{
|
|
86
|
+
kind: "radar",
|
|
87
|
+
frame: props,
|
|
88
|
+
defaultHeight: 320,
|
|
89
|
+
table: { columns: [xLabel ?? labels.category, ...table.series.map((s) => s.label)], rows: axisNames.map((a, i) => [a, ...table.series.map((s) => value(s.values[i]))]) },
|
|
90
|
+
summary,
|
|
91
|
+
isEmpty,
|
|
92
|
+
legend: /* @__PURE__ */ jsx(Legend, { items: table.series.map((s) => ({ label: s.label, color: `var(--kzc-${s.slot})` })) }),
|
|
93
|
+
engine,
|
|
94
|
+
build,
|
|
95
|
+
items
|
|
96
|
+
}
|
|
97
|
+
);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export {
|
|
101
|
+
RadarChart
|
|
102
|
+
};
|
|
103
|
+
//# sourceMappingURL=chunk-7TIFCK5E.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/radar/radar-chart.tsx"],"sourcesContent":["\"use client\";\n// Several measures of a few entities at once — models compared on latency, cost, quality — on ECharts (loaded when\n// the chart comes near the screen). The rows are the axes, the series the entities, as in a line chart.\nimport { useCallback, useMemo } from \"react\";\n\nimport { normalizeSeries, summarize, tabulate } from \"../core/data\";\nimport { categoryFormatter, valueFormatter } from \"../core/format\";\nimport { fill } from \"../core/labels\";\nimport type { Accessor, Datum, SeriesSpec, ValueFormat } from \"../core/types\";\nimport { EChartHost, type EngineProps, type WalkItem } from \"../echarts/host\";\nimport { baseOption, type ResolvedTheme, tooltipHtml } from \"../echarts/theme\";\nimport type { ChartFrameProps } from \"../web/frame\";\nimport { useSettings } from \"../web/frame\";\nimport { Legend } from \"../web/parts\";\n\nconst engine = () => import(\"../echarts/engines/radar\");\n\nexport interface RadarChartProps<T extends Datum> extends ChartFrameProps, EngineProps {\n /** One row per axis (“Latency”, “Quality”…). */\n data: readonly T[];\n /** The field (or function) naming the axis. */\n x: Accessor<T, string>;\n /** The entities compared, one value per axis each. */\n series: readonly SeriesSpec<T>[];\n /** How the values are written. */\n format?: ValueFormat;\n /** The end of every axis. Default: the largest value, rounded up. */\n max?: number;\n /** The header of the axes in the data table. */\n xLabel?: string;\n}\n\nexport function RadarChart<T extends Datum>(props: RadarChartProps<T>) {\n const { data, x, series, format, max, xLabel } = props;\n const { locale, labels } = useSettings(props);\n const specs = useMemo(() => normalizeSeries(series, undefined, undefined), [series]);\n const table = useMemo(() => tabulate(data, x, specs), [data, x, specs]);\n const value = useMemo(() => valueFormatter(format, locale, labels.noValue), [format, locale, labels.noValue]);\n const axisNames = useMemo(() => table.categories.map((c) => categoryFormatter(\"text\", locale)(c)), [table, locale]);\n const isEmpty = !data.length || !specs.length;\n const top = max ?? Math.max(1, ...table.series.flatMap((s) => s.values.map((v) => v ?? 0))) * 1.1;\n\n const summary = isEmpty\n ? labels.empty\n : [\n fill(labels.summaryIntro, { kind: labels.kinds.radar, count: `${specs.length} × ${data.length}` }),\n ...table.series.map((s) => {\n const sum = summarize(s, axisNames, String);\n return `${s.label}: ${fill(labels.summaryRange, { min: value(sum.min?.value), minAt: sum.min?.category ?? \"\", max: value(sum.max?.value), maxAt: sum.max?.category ?? \"\" })}.`;\n }),\n ].join(\" \");\n\n const items: WalkItem[] = table.series.map((s, k) => ({ seriesIndex: 0, dataIndex: k, text: `${s.label}: ${axisNames.map((a, i) => `${a} ${value(s.values[i])}`).join(\", \")}` }));\n\n const build = useCallback(\n (theme: ResolvedTheme) => ({\n ...baseOption(theme, true),\n tooltip: {\n ...(baseOption(theme, true).tooltip as object),\n trigger: \"item\",\n formatter: (p: { dataIndex: number }) => {\n const s = table.series[p.dataIndex]!;\n return tooltipHtml(s.label, axisNames.map((a, i) => ({ label: a, value: value(s.values[i]) })));\n },\n },\n radar: {\n indicator: axisNames.map((name) => ({ name, max: top })),\n radius: \"68%\",\n splitNumber: 4,\n axisName: { color: theme.text2, fontSize: 11 },\n splitLine: { lineStyle: { color: theme.grid } },\n splitArea: { show: false },\n axisLine: { lineStyle: { color: theme.grid } },\n },\n series: [\n {\n type: \"radar\",\n symbol: \"circle\",\n symbolSize: 6,\n data: table.series.map((s, k) => ({\n name: s.label,\n value: s.values.map((v) => v ?? 0),\n lineStyle: { width: 2, color: theme.palette[k % 8] },\n itemStyle: { color: theme.palette[k % 8], borderColor: theme.surface, borderWidth: 2 },\n areaStyle: { color: theme.palette[k % 8], opacity: 0.12 },\n })),\n emphasis: { lineStyle: { width: 3 }, areaStyle: { opacity: 0.25 } },\n },\n ],\n }),\n [table, axisNames, value, top],\n );\n\n return (\n <EChartHost\n kind=\"radar\"\n frame={props}\n defaultHeight={320}\n table={{ columns: [xLabel ?? labels.category, ...table.series.map((s) => s.label)], rows: axisNames.map((a, i) => [a, ...table.series.map((s) => value(s.values[i]))]) }}\n summary={summary}\n isEmpty={isEmpty}\n legend={<Legend items={table.series.map((s) => ({ label: s.label, color: `var(--kzc-${s.slot})` }))} />}\n engine={engine}\n build={build}\n items={items}\n />\n );\n}\n"],"mappings":"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","names":[]}
|