@pepperui/charts 1.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/README.md +117 -0
- package/dist/pepper-charts.js +1245 -0
- package/dist/pepper-charts.mjs +1236 -0
- package/dist/recipes.json +178 -0
- package/dist/theme.json +106 -0
- package/package.json +41 -0
- package/src/api.js +56 -0
- package/src/chartjs.js +215 -0
- package/src/echarts.js +344 -0
- package/src/format.js +119 -0
- package/src/index.js +28 -0
- package/src/mount.js +71 -0
- package/src/rules.js +306 -0
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": "1.1.0",
|
|
3
|
+
"theme": {
|
|
4
|
+
"font": "Poppins, sans-serif",
|
|
5
|
+
"text": {
|
|
6
|
+
"slide": {
|
|
7
|
+
"size": 15,
|
|
8
|
+
"weight": 400
|
|
9
|
+
},
|
|
10
|
+
"web-desktop": {
|
|
11
|
+
"size": 12,
|
|
12
|
+
"weight": 500
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"weightStrong": 600,
|
|
16
|
+
"ink": "#0b0202",
|
|
17
|
+
"grid": "#00000012",
|
|
18
|
+
"rest": "#dad9d9",
|
|
19
|
+
"onFill": "#ffffff",
|
|
20
|
+
"labelOn": {
|
|
21
|
+
"blue": {
|
|
22
|
+
"fill": "#2b25d9",
|
|
23
|
+
"ink": "#ffffff"
|
|
24
|
+
},
|
|
25
|
+
"red": {
|
|
26
|
+
"fill": "#e42521",
|
|
27
|
+
"ink": "#ffffff"
|
|
28
|
+
},
|
|
29
|
+
"yellow": {
|
|
30
|
+
"fill": "#f9c426",
|
|
31
|
+
"ink": "#0b0202"
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
"page": "#ffffff",
|
|
35
|
+
"series": {
|
|
36
|
+
"blue": [
|
|
37
|
+
"#2b25d9",
|
|
38
|
+
"#6a66e4",
|
|
39
|
+
"#d4d3f7",
|
|
40
|
+
"#b5b3b3",
|
|
41
|
+
"#dad9d9"
|
|
42
|
+
],
|
|
43
|
+
"red": [
|
|
44
|
+
"#e42521",
|
|
45
|
+
"#ec6663",
|
|
46
|
+
"#f9d3d2",
|
|
47
|
+
"#b5b3b3",
|
|
48
|
+
"#dad9d9"
|
|
49
|
+
],
|
|
50
|
+
"yellow": [
|
|
51
|
+
"#f9c426",
|
|
52
|
+
"#858080",
|
|
53
|
+
"#dad9d9",
|
|
54
|
+
"#fad567",
|
|
55
|
+
"#b5b3b3"
|
|
56
|
+
],
|
|
57
|
+
"multicolor": [
|
|
58
|
+
"#e42521",
|
|
59
|
+
"#f9c426",
|
|
60
|
+
"#2b25d9",
|
|
61
|
+
"#b5b3b3",
|
|
62
|
+
"#ec6663",
|
|
63
|
+
"#6a66e4",
|
|
64
|
+
"#fad567",
|
|
65
|
+
"#858080"
|
|
66
|
+
]
|
|
67
|
+
},
|
|
68
|
+
"$sources": {
|
|
69
|
+
"series.blue.0": "accent.blue.chart.1",
|
|
70
|
+
"series.blue.1": "accent.blue.chart.2",
|
|
71
|
+
"series.blue.2": "accent.blue.chart.3",
|
|
72
|
+
"series.blue.3": "accent.blue.chart.4",
|
|
73
|
+
"series.blue.4": "accent.blue.chart.5",
|
|
74
|
+
"series.red.0": "accent.red.chart.1",
|
|
75
|
+
"series.red.1": "accent.red.chart.2",
|
|
76
|
+
"series.red.2": "accent.red.chart.3",
|
|
77
|
+
"series.red.3": "accent.red.chart.4",
|
|
78
|
+
"series.red.4": "accent.red.chart.5",
|
|
79
|
+
"series.yellow.0": "accent.yellow.chart.1",
|
|
80
|
+
"series.yellow.1": "accent.yellow.chart.2",
|
|
81
|
+
"series.yellow.2": "accent.yellow.chart.3",
|
|
82
|
+
"series.yellow.3": "accent.yellow.chart.4",
|
|
83
|
+
"series.yellow.4": "accent.yellow.chart.5",
|
|
84
|
+
"series.multicolor.0": "accent.multicolor.chart.1",
|
|
85
|
+
"series.multicolor.1": "accent.multicolor.chart.2",
|
|
86
|
+
"series.multicolor.2": "accent.multicolor.chart.3",
|
|
87
|
+
"series.multicolor.3": "accent.multicolor.chart.4",
|
|
88
|
+
"series.multicolor.4": "accent.multicolor.chart.5",
|
|
89
|
+
"series.multicolor.5": "accent.blue.chart.2",
|
|
90
|
+
"series.multicolor.6": "accent.yellow.chart.4",
|
|
91
|
+
"series.multicolor.7": "accent.yellow.chart.2",
|
|
92
|
+
"labelOn.blue.fill": "accent.blue.chart.1",
|
|
93
|
+
"labelOn.blue.ink": "accent.blue.on-accent",
|
|
94
|
+
"labelOn.red.fill": "accent.red.chart.1",
|
|
95
|
+
"labelOn.red.ink": "accent.red.on-accent",
|
|
96
|
+
"labelOn.yellow.fill": "accent.yellow.chart.1",
|
|
97
|
+
"labelOn.yellow.ink": "accent.yellow.on-accent",
|
|
98
|
+
"text.slide": "type.slide.label.medium",
|
|
99
|
+
"text.web-desktop": "type.web-desktop.label.medium",
|
|
100
|
+
"font": "type.slide.label.medium",
|
|
101
|
+
"weightStrong": "font.weight.600",
|
|
102
|
+
"ink": "chart.text",
|
|
103
|
+
"grid": "chart.grid",
|
|
104
|
+
"rest": "chart.rest",
|
|
105
|
+
"onFill": "chart.on-fill",
|
|
106
|
+
"page": "surface.page"
|
|
107
|
+
}
|
|
108
|
+
},
|
|
109
|
+
"geometry": {
|
|
110
|
+
"axis": {
|
|
111
|
+
"baselineWidth": 2,
|
|
112
|
+
"gridWidth": 1
|
|
113
|
+
},
|
|
114
|
+
"bar": {
|
|
115
|
+
"radius": 4,
|
|
116
|
+
"maxWidth": 96
|
|
117
|
+
},
|
|
118
|
+
"line": {
|
|
119
|
+
"width": 4,
|
|
120
|
+
"symbolSize": 9
|
|
121
|
+
},
|
|
122
|
+
"area": {
|
|
123
|
+
"opacity": 0.12,
|
|
124
|
+
"forecast": {
|
|
125
|
+
"width": 3,
|
|
126
|
+
"dash": [
|
|
127
|
+
6,
|
|
128
|
+
6
|
|
129
|
+
]
|
|
130
|
+
}
|
|
131
|
+
},
|
|
132
|
+
"legend": {
|
|
133
|
+
"itemWidth": 10,
|
|
134
|
+
"itemHeight": 10,
|
|
135
|
+
"itemGap": 18
|
|
136
|
+
},
|
|
137
|
+
"grid": {
|
|
138
|
+
"left": 8,
|
|
139
|
+
"right": 40,
|
|
140
|
+
"topWithLegend": 44,
|
|
141
|
+
"top": 26,
|
|
142
|
+
"bottom": 4
|
|
143
|
+
},
|
|
144
|
+
"category": {
|
|
145
|
+
"labelGap": 12
|
|
146
|
+
},
|
|
147
|
+
"donut": {
|
|
148
|
+
"labelsOn": false,
|
|
149
|
+
"cutout": 72,
|
|
150
|
+
"segmentBorder": 3,
|
|
151
|
+
"radiusInner": "58%",
|
|
152
|
+
"radiusOuter": "85%",
|
|
153
|
+
"groupRingShare": 0.62,
|
|
154
|
+
"groupGap": 56,
|
|
155
|
+
"groupLegendMax": 380,
|
|
156
|
+
"groupLegendCharRatio": 0.55,
|
|
157
|
+
"groupLegendPad": 34,
|
|
158
|
+
"groupEdgeMin": 24,
|
|
159
|
+
"groupLegend": {
|
|
160
|
+
"itemWidth": 16,
|
|
161
|
+
"itemHeight": 16,
|
|
162
|
+
"itemGap": 22,
|
|
163
|
+
"fontSize": 20
|
|
164
|
+
},
|
|
165
|
+
"legend": {
|
|
166
|
+
"itemWidth": 14,
|
|
167
|
+
"itemHeight": 14,
|
|
168
|
+
"itemGap": 16,
|
|
169
|
+
"fontSize": 16
|
|
170
|
+
},
|
|
171
|
+
"unstyled": {
|
|
172
|
+
"cutout": 70,
|
|
173
|
+
"segmentBorder": 0,
|
|
174
|
+
"legendPct": true
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
}
|
package/dist/theme.json
ADDED
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
{
|
|
2
|
+
"font": "Poppins, sans-serif",
|
|
3
|
+
"text": {
|
|
4
|
+
"slide": {
|
|
5
|
+
"size": 15,
|
|
6
|
+
"weight": 400
|
|
7
|
+
},
|
|
8
|
+
"web-desktop": {
|
|
9
|
+
"size": 12,
|
|
10
|
+
"weight": 500
|
|
11
|
+
}
|
|
12
|
+
},
|
|
13
|
+
"weightStrong": 600,
|
|
14
|
+
"ink": "#0b0202",
|
|
15
|
+
"grid": "#00000012",
|
|
16
|
+
"rest": "#dad9d9",
|
|
17
|
+
"onFill": "#ffffff",
|
|
18
|
+
"labelOn": {
|
|
19
|
+
"blue": {
|
|
20
|
+
"fill": "#2b25d9",
|
|
21
|
+
"ink": "#ffffff"
|
|
22
|
+
},
|
|
23
|
+
"red": {
|
|
24
|
+
"fill": "#e42521",
|
|
25
|
+
"ink": "#ffffff"
|
|
26
|
+
},
|
|
27
|
+
"yellow": {
|
|
28
|
+
"fill": "#f9c426",
|
|
29
|
+
"ink": "#0b0202"
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
"page": "#ffffff",
|
|
33
|
+
"series": {
|
|
34
|
+
"blue": [
|
|
35
|
+
"#2b25d9",
|
|
36
|
+
"#6a66e4",
|
|
37
|
+
"#d4d3f7",
|
|
38
|
+
"#b5b3b3",
|
|
39
|
+
"#dad9d9"
|
|
40
|
+
],
|
|
41
|
+
"red": [
|
|
42
|
+
"#e42521",
|
|
43
|
+
"#ec6663",
|
|
44
|
+
"#f9d3d2",
|
|
45
|
+
"#b5b3b3",
|
|
46
|
+
"#dad9d9"
|
|
47
|
+
],
|
|
48
|
+
"yellow": [
|
|
49
|
+
"#f9c426",
|
|
50
|
+
"#858080",
|
|
51
|
+
"#dad9d9",
|
|
52
|
+
"#fad567",
|
|
53
|
+
"#b5b3b3"
|
|
54
|
+
],
|
|
55
|
+
"multicolor": [
|
|
56
|
+
"#e42521",
|
|
57
|
+
"#f9c426",
|
|
58
|
+
"#2b25d9",
|
|
59
|
+
"#b5b3b3",
|
|
60
|
+
"#ec6663",
|
|
61
|
+
"#6a66e4",
|
|
62
|
+
"#fad567",
|
|
63
|
+
"#858080"
|
|
64
|
+
]
|
|
65
|
+
},
|
|
66
|
+
"$sources": {
|
|
67
|
+
"series.blue.0": "accent.blue.chart.1",
|
|
68
|
+
"series.blue.1": "accent.blue.chart.2",
|
|
69
|
+
"series.blue.2": "accent.blue.chart.3",
|
|
70
|
+
"series.blue.3": "accent.blue.chart.4",
|
|
71
|
+
"series.blue.4": "accent.blue.chart.5",
|
|
72
|
+
"series.red.0": "accent.red.chart.1",
|
|
73
|
+
"series.red.1": "accent.red.chart.2",
|
|
74
|
+
"series.red.2": "accent.red.chart.3",
|
|
75
|
+
"series.red.3": "accent.red.chart.4",
|
|
76
|
+
"series.red.4": "accent.red.chart.5",
|
|
77
|
+
"series.yellow.0": "accent.yellow.chart.1",
|
|
78
|
+
"series.yellow.1": "accent.yellow.chart.2",
|
|
79
|
+
"series.yellow.2": "accent.yellow.chart.3",
|
|
80
|
+
"series.yellow.3": "accent.yellow.chart.4",
|
|
81
|
+
"series.yellow.4": "accent.yellow.chart.5",
|
|
82
|
+
"series.multicolor.0": "accent.multicolor.chart.1",
|
|
83
|
+
"series.multicolor.1": "accent.multicolor.chart.2",
|
|
84
|
+
"series.multicolor.2": "accent.multicolor.chart.3",
|
|
85
|
+
"series.multicolor.3": "accent.multicolor.chart.4",
|
|
86
|
+
"series.multicolor.4": "accent.multicolor.chart.5",
|
|
87
|
+
"series.multicolor.5": "accent.blue.chart.2",
|
|
88
|
+
"series.multicolor.6": "accent.yellow.chart.4",
|
|
89
|
+
"series.multicolor.7": "accent.yellow.chart.2",
|
|
90
|
+
"labelOn.blue.fill": "accent.blue.chart.1",
|
|
91
|
+
"labelOn.blue.ink": "accent.blue.on-accent",
|
|
92
|
+
"labelOn.red.fill": "accent.red.chart.1",
|
|
93
|
+
"labelOn.red.ink": "accent.red.on-accent",
|
|
94
|
+
"labelOn.yellow.fill": "accent.yellow.chart.1",
|
|
95
|
+
"labelOn.yellow.ink": "accent.yellow.on-accent",
|
|
96
|
+
"text.slide": "type.slide.label.medium",
|
|
97
|
+
"text.web-desktop": "type.web-desktop.label.medium",
|
|
98
|
+
"font": "type.slide.label.medium",
|
|
99
|
+
"weightStrong": "font.weight.600",
|
|
100
|
+
"ink": "chart.text",
|
|
101
|
+
"grid": "chart.grid",
|
|
102
|
+
"rest": "chart.rest",
|
|
103
|
+
"onFill": "chart.on-fill",
|
|
104
|
+
"page": "surface.page"
|
|
105
|
+
}
|
|
106
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@pepperui/charts",
|
|
3
|
+
"version": "1.1.0",
|
|
4
|
+
"description": "The Mobupps design system's chart theme (DL-10): per-accent series palettes, the two-slice donut rule, the narrow-band axis floor and the shared number-format object, generated from @pepperui/tokens. One palette, four renderers — ECharts, Chart.js, the PPTX exporter and the Figma chart recipes.",
|
|
5
|
+
"license": "UNLICENSED",
|
|
6
|
+
"private": false,
|
|
7
|
+
"type": "module",
|
|
8
|
+
"files": [
|
|
9
|
+
"dist",
|
|
10
|
+
"src",
|
|
11
|
+
"README.md"
|
|
12
|
+
],
|
|
13
|
+
"main": "./dist/pepper-charts.js",
|
|
14
|
+
"module": "./dist/pepper-charts.mjs",
|
|
15
|
+
"exports": {
|
|
16
|
+
".": {
|
|
17
|
+
"import": "./dist/pepper-charts.mjs",
|
|
18
|
+
"default": "./dist/pepper-charts.js"
|
|
19
|
+
},
|
|
20
|
+
"./theme.json": "./dist/theme.json",
|
|
21
|
+
"./browser": "./dist/pepper-charts.js",
|
|
22
|
+
"./src/*": "./src/*"
|
|
23
|
+
},
|
|
24
|
+
"publishConfig": {
|
|
25
|
+
"access": "public"
|
|
26
|
+
},
|
|
27
|
+
"repository": {
|
|
28
|
+
"type": "git",
|
|
29
|
+
"url": "git+ssh://git@bitbucket.org/rashidmobupps/pepper-ui.git",
|
|
30
|
+
"directory": "packages/charts"
|
|
31
|
+
},
|
|
32
|
+
"keywords": [
|
|
33
|
+
"charts",
|
|
34
|
+
"echarts",
|
|
35
|
+
"chart.js",
|
|
36
|
+
"design-system",
|
|
37
|
+
"data-visualisation",
|
|
38
|
+
"mobupps",
|
|
39
|
+
"pepper-ui"
|
|
40
|
+
]
|
|
41
|
+
}
|
package/src/api.js
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/* ============================================================================
|
|
2
|
+
api — what the package is, from the outside.
|
|
3
|
+
|
|
4
|
+
`dist/pepper-charts.js` assigns this to `window.PepperCharts`; the ESM build
|
|
5
|
+
exports it as the default and every member by name. The four names Paggy's own
|
|
6
|
+
code already calls — `renderAll`, `buildOption`, `refit`, `valueFormatter` —
|
|
7
|
+
keep their signatures exactly, so adopting the package is a delivery, not a
|
|
8
|
+
rewrite.
|
|
9
|
+
============================================================================ */
|
|
10
|
+
const PepperCharts = {
|
|
11
|
+
/** the package version, and the token build it was generated from */
|
|
12
|
+
version: VERSION,
|
|
13
|
+
/** the GENERATED theme: palettes, ink, grid, rest, on-fill, type. Read it, do
|
|
14
|
+
* not write it — every value traces to a token through `theme.$sources`. */
|
|
15
|
+
theme: THEME,
|
|
16
|
+
/** the chart-recipe geometry (radii, legend markers, grid lanes, donut ring) */
|
|
17
|
+
geometry: GEOMETRY,
|
|
18
|
+
|
|
19
|
+
/* the palette */
|
|
20
|
+
/** series `i` of `accent`; pass `count` so a TWO-series chart gets RULE 12's `chart/rest` */
|
|
21
|
+
seriesColor: (accent, i, count) => seriesColor(THEME, accent, i, count),
|
|
22
|
+
palette,
|
|
23
|
+
sliceColor: (accent, labels, i, explicit) => sliceColor(THEME, accent, labels, i, explicit),
|
|
24
|
+
/** the ink of a label written inside `fill` — the accent's own on a main fill, `onFill` elsewhere (D110) */
|
|
25
|
+
labelInk: (fill) => labelInk(THEME, fill),
|
|
26
|
+
|
|
27
|
+
/* the rules */
|
|
28
|
+
narrowBandFloor,
|
|
29
|
+
isTwoSlice,
|
|
30
|
+
/** RULE 9 — one colour per bar for a one-series chart: 'flat' (the accent's
|
|
31
|
+
* chart/1), 'tints' (its chart/1–5) or 'multicolor' (the red→yellow→blue→gray
|
|
32
|
+
* cycle). All three are correct; this is where every channel reads them. */
|
|
33
|
+
barColors: (accent, n, treatment) => barColors(THEME, accent, n, treatment),
|
|
34
|
+
/** RULES 3 and 4 — the four-corner radius of a bar; `stack` is 'last' for the
|
|
35
|
+
* top segment of a stack and 'mid' for the ones below it */
|
|
36
|
+
barRadius,
|
|
37
|
+
/** the rendered width of a string in the chart's own type (RULE 7, D16) */
|
|
38
|
+
textWidth,
|
|
39
|
+
/** a hex at an opacity, as rgba — RULE 10's band in the renderer that wants one value */
|
|
40
|
+
withAlpha,
|
|
41
|
+
|
|
42
|
+
/* the numbers */
|
|
43
|
+
valueFormatter,
|
|
44
|
+
formatter,
|
|
45
|
+
|
|
46
|
+
/* ECharts */
|
|
47
|
+
echartsTheme,
|
|
48
|
+
buildOption,
|
|
49
|
+
|
|
50
|
+
/* Chart.js — the same theme as pieces to spread into its options */
|
|
51
|
+
chartjs,
|
|
52
|
+
|
|
53
|
+
/* the DOM adapter */
|
|
54
|
+
renderAll,
|
|
55
|
+
refit,
|
|
56
|
+
};
|
package/src/chartjs.js
ADDED
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
/* ============================================================================
|
|
2
|
+
Chart.js — the same theme, the other renderer (3.1.2).
|
|
3
|
+
|
|
4
|
+
Chart.js has no option builder here the way ECharts does, and deliberately: its
|
|
5
|
+
consumers (the quarter builder's six chart layouts) each compose their own chart
|
|
6
|
+
from a generated template, and what they were repeating was not a chart — it was
|
|
7
|
+
the same ink, the same grid, the same 15px Poppins and the same 4px bar top,
|
|
8
|
+
typed out thirty-odd times. So this part hands out those PIECES, each one a plain
|
|
9
|
+
object ready to spread into a Chart.js option:
|
|
10
|
+
|
|
11
|
+
ticks: PepperCharts.chartjs.text(),
|
|
12
|
+
grid: PepperCharts.chartjs.grid(), border: { display: false },
|
|
13
|
+
...PepperCharts.chartjs.bar(),
|
|
14
|
+
|
|
15
|
+
`defaults()` sets the globals once, and everything below is what a chart still has
|
|
16
|
+
to say for itself. Same THEME as the ECharts side, so the two renderers cannot
|
|
17
|
+
disagree about a colour (DL-10, G13).
|
|
18
|
+
============================================================================ */
|
|
19
|
+
|
|
20
|
+
/** Apply the house globals to `Chart.defaults`. Call it once, after Chart.js loads.
|
|
21
|
+
* Returns what it set, so a caller can log or assert it. */
|
|
22
|
+
function chartjsDefaults(canvas, Chart) {
|
|
23
|
+
const C = Chart || (typeof window !== 'undefined' ? window.Chart : undefined);
|
|
24
|
+
const t = chartText(canvas);
|
|
25
|
+
const set = { 'font.family': THEME.font, 'font.size': t.size, color: THEME.ink };
|
|
26
|
+
if (C && C.defaults) {
|
|
27
|
+
C.defaults.font.family = THEME.font;
|
|
28
|
+
C.defaults.font.size = t.size;
|
|
29
|
+
C.defaults.color = THEME.ink;
|
|
30
|
+
}
|
|
31
|
+
return set;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/** The accent's series colours, as Chart.js wants them: a plain array. `count` is how many series
|
|
35
|
+
* the chart draws — with exactly two, RULE 12 makes the second one `chart/rest`. */
|
|
36
|
+
function chartjsPalette(accent, count) {
|
|
37
|
+
const base = (THEME.series[accent] || THEME.series.blue).slice();
|
|
38
|
+
if (count === 2) return [base[0], THEME.rest];
|
|
39
|
+
return base;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/** A font block on its own: the canvas role's size (or an override) and the family.
|
|
43
|
+
* A total drawn bigger than its bars is the chart's own decision, not the theme's,
|
|
44
|
+
* so a size may be passed; the family never varies. */
|
|
45
|
+
function chartjsFont(canvas, size, weight) {
|
|
46
|
+
return { size: size || chartText(canvas).size, family: THEME.font, ...(weight ? { weight } : {}) };
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/** Text in a chart — ticks, legend labels, anything Chart.js styles with
|
|
50
|
+
* `{ font, color }`. No family: `defaults()` set it globally, and the smaller the
|
|
51
|
+
* option the easier it is to read what a chart actually overrides. */
|
|
52
|
+
function chartjsText(canvas, size) {
|
|
53
|
+
return { font: { size: size || chartText(canvas).size }, color: THEME.ink };
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/** The same, with the family stated. The datalabels plugin draws on its own canvas
|
|
57
|
+
* context and does not inherit `Chart.defaults.font.family`, so a data label says
|
|
58
|
+
* the family itself. */
|
|
59
|
+
function chartjsLabel(canvas, size, weight) {
|
|
60
|
+
return { font: chartjsFont(canvas, size, weight), color: THEME.ink };
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/** RULE 2 — a light line at every tick, behind the bars. */
|
|
64
|
+
function chartjsGrid() { return { color: THEME.grid, lineWidth: GEOMETRY.axis.gridWidth }; }
|
|
65
|
+
|
|
66
|
+
/** A value axis draws no line of its own. */
|
|
67
|
+
function chartjsBorder() { return { display: false }; }
|
|
68
|
+
|
|
69
|
+
/** RULE 1 — the baseline the columns stand on: `chart/rest` at 2px, heavier than
|
|
70
|
+
* the grid. It goes on the CATEGORY axis, whose border is the line at zero. Until
|
|
71
|
+
* 2026-09-21 this file said *"the axis line that is never drawn"* and meant it —
|
|
72
|
+
* the first thing he marked on the audit (D1). */
|
|
73
|
+
function chartjsBaseline() {
|
|
74
|
+
return { display: true, color: THEME.rest, width: GEOMETRY.axis.baselineWidth };
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/** RULE 3 — a bar dataset's house shape: 4px on the top corners, square at the
|
|
78
|
+
* foot. `borderSkipped: false` used to round the bottom too, so a deck's column
|
|
79
|
+
* floated as a pill while the same column in a dashboard sat flat (D2); Chart.js'
|
|
80
|
+
* own default skips the start edge, which is exactly the rule. */
|
|
81
|
+
function chartjsBar() {
|
|
82
|
+
return { borderRadius: GEOMETRY.bar.radius };
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/** RULE 4 — a segment of a STACKED bar: the top one rounds, the joints stay
|
|
86
|
+
* square. `last` is true for the dataset drawn at the top of the stack. */
|
|
87
|
+
function chartjsStacked(last) {
|
|
88
|
+
return { borderRadius: last ? GEOMETRY.bar.radius : 0 };
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/** RULE 5 — a line dataset: the 4px spline with a dot at every point. The dots
|
|
92
|
+
* reverse what this renderer drew until 2026-09-21; ECharts drew them, Chart.js
|
|
93
|
+
* did not, and he picked them on the pair (D14). */
|
|
94
|
+
function chartjsLine() {
|
|
95
|
+
return {
|
|
96
|
+
borderWidth: GEOMETRY.line.width,
|
|
97
|
+
pointRadius: GEOMETRY.line.symbolSize / 2,
|
|
98
|
+
pointHoverRadius: GEOMETRY.line.symbolSize / 2,
|
|
99
|
+
tension: 0.35,
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/** RULES 10 and 11 — the forecast band and the dashed line over it, as the two
|
|
104
|
+
* dataset blocks a Chart.js consumer spreads. `accent` picks the band's colour;
|
|
105
|
+
* the line is that accent's `chart/4`. */
|
|
106
|
+
function chartjsArea(accent) {
|
|
107
|
+
return {
|
|
108
|
+
...chartjsLine(),
|
|
109
|
+
pointRadius: 0,
|
|
110
|
+
fill: 'origin',
|
|
111
|
+
backgroundColor: withAlpha(seriesColor(THEME, accent, 0), GEOMETRY.area.opacity),
|
|
112
|
+
borderColor: seriesColor(THEME, accent, 0),
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function chartjsForecast(accent) {
|
|
117
|
+
const c = seriesColor(THEME, accent, 3);
|
|
118
|
+
return {
|
|
119
|
+
borderWidth: GEOMETRY.area.forecast.width,
|
|
120
|
+
borderDash: GEOMETRY.area.forecast.dash.slice(),
|
|
121
|
+
borderColor: c,
|
|
122
|
+
pointRadius: 0,
|
|
123
|
+
fill: false,
|
|
124
|
+
tension: 0.35,
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/** RULE 9 — the three treatments of a ONE-SERIES chart, as the per-bar colour
|
|
129
|
+
* array Chart.js takes. This is what the renderer did not have: a deck painted a
|
|
130
|
+
* multicolor chart entirely red and could not follow the three-colour rule, and
|
|
131
|
+
* the site wrote its own cycler because the package handed it none (D17). One
|
|
132
|
+
* rule, one place, three consumers. */
|
|
133
|
+
function chartjsBarColors(accent, n, treatment) {
|
|
134
|
+
return barColors(THEME, accent, n, treatment);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/** A doughnut: the ring and its borders. `cutout` overrides the house 72% for a
|
|
138
|
+
* consumer that draws a thinner ring, and is a stated substitution when it does. */
|
|
139
|
+
function chartjsDoughnut(cutout) {
|
|
140
|
+
return {
|
|
141
|
+
cutout: (cutout == null ? GEOMETRY.donut.cutout : cutout) + '%',
|
|
142
|
+
borderWidth: GEOMETRY.donut.segmentBorder,
|
|
143
|
+
borderColor: THEME.onFill,
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/** The legend block: circular markers in the chart's own text. `extra` is merged
|
|
148
|
+
* into `labels`, which is where a consumer puts its padding or its
|
|
149
|
+
* `generateLabels`. */
|
|
150
|
+
function chartjsLegendLabels(canvas, extra) {
|
|
151
|
+
return {
|
|
152
|
+
...chartjsText(canvas),
|
|
153
|
+
usePointStyle: true,
|
|
154
|
+
pointStyle: 'circle',
|
|
155
|
+
...(extra || {}),
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
function chartjsLegend(canvas, extra) {
|
|
160
|
+
return { labels: chartjsLegendLabels(canvas, extra) };
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/** A value axis: the grid, no border, the ticks in chart text, and — when the data
|
|
164
|
+
* is handed in — the narrow-band floor as `min`, so a Chart.js chart of uptime
|
|
165
|
+
* reads the way the ECharts one does. An explicit `min` always wins. */
|
|
166
|
+
function chartjsValueAxis(canvas, opts) {
|
|
167
|
+
const o = opts || {};
|
|
168
|
+
const floor = o.values ? narrowBandFloor(o.values) : undefined;
|
|
169
|
+
const min = o.min != null ? o.min : floor;
|
|
170
|
+
return {
|
|
171
|
+
...(min != null ? { min } : {}),
|
|
172
|
+
...(o.max != null ? { max: o.max } : {}),
|
|
173
|
+
ticks: { ...chartjsText(canvas), ...(o.ticks || {}) },
|
|
174
|
+
grid: chartjsGrid(),
|
|
175
|
+
border: chartjsBorder(),
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/** A category axis: no grid, the baseline, every label kept. */
|
|
180
|
+
function chartjsCategoryAxis(canvas, opts) {
|
|
181
|
+
const o = opts || {};
|
|
182
|
+
return {
|
|
183
|
+
ticks: { autoSkip: false, ...chartjsText(canvas, o.size), ...(o.ticks || {}) },
|
|
184
|
+
grid: { display: false },
|
|
185
|
+
// RULE 1 — the category axis carries the baseline
|
|
186
|
+
border: chartjsBaseline(),
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/** Everything above, as one object — `PepperCharts.chartjs.*`. */
|
|
191
|
+
const chartjs = {
|
|
192
|
+
defaults: chartjsDefaults,
|
|
193
|
+
palette: chartjsPalette,
|
|
194
|
+
color: (accent, i, count) => seriesColor(THEME, accent, i, count),
|
|
195
|
+
ink: () => THEME.ink,
|
|
196
|
+
family: () => THEME.font,
|
|
197
|
+
size: (canvas) => chartText(canvas).size,
|
|
198
|
+
font: chartjsFont,
|
|
199
|
+
text: chartjsText,
|
|
200
|
+
label: chartjsLabel,
|
|
201
|
+
labels: chartjsLegendLabels,
|
|
202
|
+
grid: chartjsGrid,
|
|
203
|
+
border: chartjsBorder,
|
|
204
|
+
baseline: chartjsBaseline,
|
|
205
|
+
bar: chartjsBar,
|
|
206
|
+
stacked: chartjsStacked,
|
|
207
|
+
line: chartjsLine,
|
|
208
|
+
area: chartjsArea,
|
|
209
|
+
forecast: chartjsForecast,
|
|
210
|
+
barColors: chartjsBarColors,
|
|
211
|
+
doughnut: chartjsDoughnut,
|
|
212
|
+
legend: chartjsLegend,
|
|
213
|
+
valueAxis: chartjsValueAxis,
|
|
214
|
+
categoryAxis: chartjsCategoryAxis,
|
|
215
|
+
};
|