gwchq-textjam 0.1.8 → 0.1.9
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.txt +202 -202
- package/README.md +253 -256
- package/dist/assets/{PyodideWorkerdf6f34ea7e2b4495f8d4.js → PyodideWorker917534d142d1f853d376.js} +528 -528
- package/dist/assets/{pygalef3b78a56cb1d66beb61.js → pygalc0b4f32d2d2cc5a0c638.js} +495 -495
- package/dist/index.js +4713 -6028
- package/dist/style.css +8 -9
- package/package.json +268 -268
|
@@ -1,495 +1,495 @@
|
|
|
1
|
-
/* global globalThis */
|
|
2
|
-
|
|
3
|
-
var pygal = {};
|
|
4
|
-
|
|
5
|
-
pygal.config = {
|
|
6
|
-
renderChart: (chart) => {
|
|
7
|
-
throw new Error(
|
|
8
|
-
"The config.renderChart function has not been set for pygal.",
|
|
9
|
-
);
|
|
10
|
-
},
|
|
11
|
-
availableWidth: 400,
|
|
12
|
-
availableHeight: 300,
|
|
13
|
-
};
|
|
14
|
-
|
|
15
|
-
const COLORS = [
|
|
16
|
-
[255, 89, 149],
|
|
17
|
-
[182, 227, 84],
|
|
18
|
-
[254, 237, 108],
|
|
19
|
-
[140, 237, 255],
|
|
20
|
-
[158, 111, 254],
|
|
21
|
-
[137, 156, 161],
|
|
22
|
-
[248, 248, 242],
|
|
23
|
-
[191, 70, 70],
|
|
24
|
-
[81, 96, 131],
|
|
25
|
-
[249, 38, 114],
|
|
26
|
-
[130, 180, 20],
|
|
27
|
-
[253, 151, 31],
|
|
28
|
-
[86, 194, 214],
|
|
29
|
-
[128, 131, 132],
|
|
30
|
-
[140, 84, 254],
|
|
31
|
-
[70, 84, 87],
|
|
32
|
-
];
|
|
33
|
-
|
|
34
|
-
const some = (val) => typeof val !== "undefined";
|
|
35
|
-
pygal.toJs = (val) => (val?.toJs ? val.toJs() : val);
|
|
36
|
-
|
|
37
|
-
class Chart {
|
|
38
|
-
constructor({
|
|
39
|
-
title,
|
|
40
|
-
width,
|
|
41
|
-
height,
|
|
42
|
-
range,
|
|
43
|
-
include_x_axis,
|
|
44
|
-
x_title,
|
|
45
|
-
y_title,
|
|
46
|
-
title_font_size,
|
|
47
|
-
fill,
|
|
48
|
-
stroke,
|
|
49
|
-
x_labels,
|
|
50
|
-
} = {}) {
|
|
51
|
-
const options = {};
|
|
52
|
-
if (some(title)) options.title = pygal.toJs(title);
|
|
53
|
-
if (some(width)) options.width = pygal.toJs(width);
|
|
54
|
-
if (some(height)) options.height = pygal.toJs(height);
|
|
55
|
-
if (some(range))
|
|
56
|
-
options.range = {
|
|
57
|
-
min: pygal.toJs(range)[0],
|
|
58
|
-
max: pygal.toJs(range)[1],
|
|
59
|
-
};
|
|
60
|
-
if (some(include_x_axis))
|
|
61
|
-
options.include_x_axis = pygal.toJs(include_x_axis);
|
|
62
|
-
if (some(x_title)) options.x_title = pygal.toJs(x_title);
|
|
63
|
-
if (some(y_title)) options.y_title = pygal.toJs(y_title);
|
|
64
|
-
if (some(title_font_size))
|
|
65
|
-
options.title_font_size = pygal.toJs(title_font_size);
|
|
66
|
-
if (some(fill)) options.fill = pygal.toJs(fill);
|
|
67
|
-
if (some(stroke)) options.stroke = pygal.toJs(stroke);
|
|
68
|
-
if (some(x_labels)) options.x_labels = pygal.toJs(x_labels);
|
|
69
|
-
|
|
70
|
-
this._options = options;
|
|
71
|
-
this._data = [];
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
add(label, values) {
|
|
75
|
-
if (!Array.isArray(pygal.toJs(values))) {
|
|
76
|
-
values = [values];
|
|
77
|
-
}
|
|
78
|
-
const data = [...pygal.toJs(values)].map((v) => v || 0);
|
|
79
|
-
|
|
80
|
-
this._data.unshift({
|
|
81
|
-
name: pygal.toJs(label),
|
|
82
|
-
color: this.#rgba(COLORS[this._data.length % COLORS.length], 0.75),
|
|
83
|
-
data: data,
|
|
84
|
-
marker: {
|
|
85
|
-
symbol: "circle",
|
|
86
|
-
},
|
|
87
|
-
stack: 1,
|
|
88
|
-
});
|
|
89
|
-
|
|
90
|
-
return "";
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
render() {
|
|
94
|
-
const options = this._options;
|
|
95
|
-
const title_style = {
|
|
96
|
-
color: "#FFFFFF",
|
|
97
|
-
};
|
|
98
|
-
if (options.title_font_size) {
|
|
99
|
-
title_style["font-size"] = options.title_font_size + "px";
|
|
100
|
-
}
|
|
101
|
-
const yPlotLines = [];
|
|
102
|
-
|
|
103
|
-
if (options.range) {
|
|
104
|
-
yPlotLines.push({
|
|
105
|
-
value: options.range.min,
|
|
106
|
-
width: 1,
|
|
107
|
-
color: "#FFFFFF",
|
|
108
|
-
});
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
const defaultWidth = pygal.config.availableWidth;
|
|
112
|
-
const defaultHeight = Math.min(defaultWidth, pygal.config.availableHeight);
|
|
113
|
-
|
|
114
|
-
let chart = {
|
|
115
|
-
chart: {
|
|
116
|
-
width: options.width || defaultWidth,
|
|
117
|
-
height: options.height || defaultHeight,
|
|
118
|
-
backgroundColor: "#000",
|
|
119
|
-
},
|
|
120
|
-
credits: {
|
|
121
|
-
enabled: false,
|
|
122
|
-
},
|
|
123
|
-
title: {
|
|
124
|
-
text: options.title,
|
|
125
|
-
style: title_style,
|
|
126
|
-
},
|
|
127
|
-
xAxis: {
|
|
128
|
-
title: {
|
|
129
|
-
text: options.x_title || null,
|
|
130
|
-
style: title_style,
|
|
131
|
-
margin: 20,
|
|
132
|
-
},
|
|
133
|
-
categories: options.x_labels,
|
|
134
|
-
labels: {
|
|
135
|
-
enabled: options.x_labels ? true : false,
|
|
136
|
-
},
|
|
137
|
-
tickLength: 0,
|
|
138
|
-
},
|
|
139
|
-
yAxis: {
|
|
140
|
-
startOnTick: false,
|
|
141
|
-
title: {
|
|
142
|
-
text: options.y_title || null,
|
|
143
|
-
style: title_style,
|
|
144
|
-
margin: 20,
|
|
145
|
-
},
|
|
146
|
-
plotLines: yPlotLines,
|
|
147
|
-
min: options.include_x_axis
|
|
148
|
-
? 0
|
|
149
|
-
: options.range
|
|
150
|
-
? options.range.min
|
|
151
|
-
: null,
|
|
152
|
-
max: options.range ? options.range.max : null,
|
|
153
|
-
gridLineDashStyle: "ShortDash",
|
|
154
|
-
gridLineColor: "#DDD",
|
|
155
|
-
tickLength: 0,
|
|
156
|
-
},
|
|
157
|
-
legend: {
|
|
158
|
-
itemStyle: {
|
|
159
|
-
color: "#FFFFFF",
|
|
160
|
-
},
|
|
161
|
-
layout: "vertical",
|
|
162
|
-
align: "left",
|
|
163
|
-
verticalAlign: "top",
|
|
164
|
-
y: 50,
|
|
165
|
-
borderWidth: 0,
|
|
166
|
-
},
|
|
167
|
-
labels: {
|
|
168
|
-
style: {
|
|
169
|
-
color: "#FFFFFF",
|
|
170
|
-
},
|
|
171
|
-
},
|
|
172
|
-
series: this._data,
|
|
173
|
-
};
|
|
174
|
-
|
|
175
|
-
for (let i = 0; i < chart.series.length; i++) {
|
|
176
|
-
chart.series[i].legendIndex = chart.series.length - i;
|
|
177
|
-
chart.series[i].index = chart.series.length - i;
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
if (this.renderer) {
|
|
181
|
-
chart = this.renderer(options, chart);
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
pygal.config.renderChart(chart);
|
|
185
|
-
|
|
186
|
-
return "";
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
get title() {
|
|
190
|
-
return this._options.title;
|
|
191
|
-
}
|
|
192
|
-
get width() {
|
|
193
|
-
return this._options.width;
|
|
194
|
-
}
|
|
195
|
-
get height() {
|
|
196
|
-
return this._options.height;
|
|
197
|
-
}
|
|
198
|
-
get range() {
|
|
199
|
-
return this._options.range;
|
|
200
|
-
}
|
|
201
|
-
get include_x_axis() {
|
|
202
|
-
return this._options.include_x_axis;
|
|
203
|
-
}
|
|
204
|
-
get x_title() {
|
|
205
|
-
return this._options.x_title;
|
|
206
|
-
}
|
|
207
|
-
get y_title() {
|
|
208
|
-
return this._options.y_title;
|
|
209
|
-
}
|
|
210
|
-
get title_font_size() {
|
|
211
|
-
return this._options.title_font_size;
|
|
212
|
-
}
|
|
213
|
-
get fill() {
|
|
214
|
-
return this._options.fill;
|
|
215
|
-
}
|
|
216
|
-
get stroke() {
|
|
217
|
-
return this._options.stroke;
|
|
218
|
-
}
|
|
219
|
-
get x_labels() {
|
|
220
|
-
return this._options.x_labels;
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
set title(val) {
|
|
224
|
-
this._options.title = pygal.toJs(val);
|
|
225
|
-
}
|
|
226
|
-
set width(val) {
|
|
227
|
-
this._options.width = pygal.toJs(val);
|
|
228
|
-
}
|
|
229
|
-
set height(val) {
|
|
230
|
-
this._options.height = pygal.toJs(val);
|
|
231
|
-
}
|
|
232
|
-
set range(val) {
|
|
233
|
-
this._options.range = pygal.toJs(val);
|
|
234
|
-
}
|
|
235
|
-
set include_x_axis(val) {
|
|
236
|
-
this._options.include_x_axis = pygal.toJs(val);
|
|
237
|
-
}
|
|
238
|
-
set x_title(val) {
|
|
239
|
-
this._options.x_title = pygal.toJs(val);
|
|
240
|
-
}
|
|
241
|
-
set y_title(val) {
|
|
242
|
-
this._options.y_title = pygal.toJs(val);
|
|
243
|
-
}
|
|
244
|
-
set title_font_size(val) {
|
|
245
|
-
this._options.title_font_size = pygal.toJs(val);
|
|
246
|
-
}
|
|
247
|
-
set fill(val) {
|
|
248
|
-
this._options.fill = pygal.toJs(val);
|
|
249
|
-
}
|
|
250
|
-
set stroke(val) {
|
|
251
|
-
this._options.stroke = pygal.toJs(val);
|
|
252
|
-
}
|
|
253
|
-
set x_labels(val) {
|
|
254
|
-
this._options.x_labels = pygal.toJs(val);
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
#rgba(rgb, a) {
|
|
258
|
-
return "rgba(" + rgb.join(",") + "," + a + ")";
|
|
259
|
-
}
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
// Work around a webpack hot module reloading problem.
|
|
263
|
-
globalThis.$RefreshReg$ = () => {};
|
|
264
|
-
|
|
265
|
-
class _Line extends Chart {
|
|
266
|
-
constructor(...args) {
|
|
267
|
-
super(...args);
|
|
268
|
-
this.renderer = (options, chart) => {
|
|
269
|
-
chart.chart.type = pygal.toJs(options.fill) ? "area" : "line";
|
|
270
|
-
return chart;
|
|
271
|
-
};
|
|
272
|
-
}
|
|
273
|
-
}
|
|
274
|
-
const Line = (...args) => new _Line(...args);
|
|
275
|
-
|
|
276
|
-
class _StackedLine extends Chart {
|
|
277
|
-
constructor(...args) {
|
|
278
|
-
super(...args);
|
|
279
|
-
this.renderer = (options, chart) => {
|
|
280
|
-
chart.chart.type = pygal.toJs(options.fill) ? "area" : "line";
|
|
281
|
-
chart.plotOptions = {
|
|
282
|
-
area: {
|
|
283
|
-
stacking: "percent",
|
|
284
|
-
},
|
|
285
|
-
series: {
|
|
286
|
-
stacking: "percent",
|
|
287
|
-
},
|
|
288
|
-
};
|
|
289
|
-
return chart;
|
|
290
|
-
};
|
|
291
|
-
}
|
|
292
|
-
}
|
|
293
|
-
const StackedLine = (...args) => new _StackedLine(...args);
|
|
294
|
-
|
|
295
|
-
class _Bar extends Chart {
|
|
296
|
-
constructor(...args) {
|
|
297
|
-
super(...args);
|
|
298
|
-
this.renderer = (options, chart) => {
|
|
299
|
-
chart.chart.type = "column";
|
|
300
|
-
return chart;
|
|
301
|
-
};
|
|
302
|
-
}
|
|
303
|
-
}
|
|
304
|
-
const Bar = (...args) => new _Bar(...args);
|
|
305
|
-
|
|
306
|
-
class _StackedBar extends Chart {
|
|
307
|
-
constructor(...args) {
|
|
308
|
-
super(...args);
|
|
309
|
-
this.renderer = (options, chart) => {
|
|
310
|
-
chart.chart.type = "column";
|
|
311
|
-
chart.plotOptions = {
|
|
312
|
-
column: {
|
|
313
|
-
stacking: "percent",
|
|
314
|
-
},
|
|
315
|
-
};
|
|
316
|
-
return chart;
|
|
317
|
-
};
|
|
318
|
-
}
|
|
319
|
-
}
|
|
320
|
-
const StackedBar = (...args) => new _StackedBar(...args);
|
|
321
|
-
|
|
322
|
-
class _HorizontalBar extends Chart {
|
|
323
|
-
constructor(...args) {
|
|
324
|
-
super(...args);
|
|
325
|
-
this.renderer = (options, chart) => {
|
|
326
|
-
chart.chart.type = "bar";
|
|
327
|
-
return chart;
|
|
328
|
-
};
|
|
329
|
-
}
|
|
330
|
-
}
|
|
331
|
-
const HorizontalBar = (...args) => new _HorizontalBar(...args);
|
|
332
|
-
|
|
333
|
-
class _StackedHorizontalBar extends Chart {
|
|
334
|
-
constructor(...args) {
|
|
335
|
-
super(...args);
|
|
336
|
-
this.renderer = (options, chart) => {
|
|
337
|
-
chart.chart.type = "bar";
|
|
338
|
-
chart.plotOptions = {
|
|
339
|
-
bar: {
|
|
340
|
-
stacking: "percent",
|
|
341
|
-
},
|
|
342
|
-
};
|
|
343
|
-
return chart;
|
|
344
|
-
};
|
|
345
|
-
}
|
|
346
|
-
}
|
|
347
|
-
const StackedHorizontalBar = (...args) => new _StackedHorizontalBar(...args);
|
|
348
|
-
|
|
349
|
-
class _XY extends Chart {
|
|
350
|
-
constructor(...args) {
|
|
351
|
-
super(...args);
|
|
352
|
-
this.renderer = (options, chart) => {
|
|
353
|
-
if (pygal.toJs(options.stroke) === false) {
|
|
354
|
-
chart.chart.type = "scatter";
|
|
355
|
-
} else {
|
|
356
|
-
chart.chart.type = pygal.toJs(options.fill) ? "area" : "line";
|
|
357
|
-
}
|
|
358
|
-
chart.xAxis.labels.enabled = true;
|
|
359
|
-
|
|
360
|
-
return chart;
|
|
361
|
-
};
|
|
362
|
-
}
|
|
363
|
-
}
|
|
364
|
-
const XY = (...args) => new _XY(...args);
|
|
365
|
-
|
|
366
|
-
class _Radar extends Chart {
|
|
367
|
-
constructor(...args) {
|
|
368
|
-
super(...args);
|
|
369
|
-
this.renderer = (options, chart) => {
|
|
370
|
-
chart.chart.polar = true;
|
|
371
|
-
chart.chart.type = "line";
|
|
372
|
-
chart.xAxis = {
|
|
373
|
-
categories: pygal.toJs(options.x_labels),
|
|
374
|
-
tickmarkPlacement: "on",
|
|
375
|
-
lineWidth: 0,
|
|
376
|
-
};
|
|
377
|
-
chart.yAxis = {
|
|
378
|
-
gridLineInterpolation: "polygon",
|
|
379
|
-
lineWidth: 0,
|
|
380
|
-
min: 0,
|
|
381
|
-
gridLineDashStyle: "ShortDash",
|
|
382
|
-
gridLineColor: "#DDD",
|
|
383
|
-
};
|
|
384
|
-
for (let i = 0; i < chart.series.length; i++) {
|
|
385
|
-
chart.series[i].pointPlacement = "on";
|
|
386
|
-
}
|
|
387
|
-
|
|
388
|
-
return chart;
|
|
389
|
-
};
|
|
390
|
-
}
|
|
391
|
-
}
|
|
392
|
-
const Radar = (...args) => new _Radar(...args);
|
|
393
|
-
|
|
394
|
-
class _Pie extends Chart {
|
|
395
|
-
constructor(...args) {
|
|
396
|
-
super(...args);
|
|
397
|
-
this.renderer = (options, chart) => {
|
|
398
|
-
chart.chart.type = "pie";
|
|
399
|
-
const slices = [];
|
|
400
|
-
const breakdown = [];
|
|
401
|
-
let useBreakdown = false;
|
|
402
|
-
for (let i = 0; i < chart.series.length; i++) {
|
|
403
|
-
const slice = chart.series[i];
|
|
404
|
-
if (slice.data.length === 1) {
|
|
405
|
-
slices.unshift({
|
|
406
|
-
name: slice.name,
|
|
407
|
-
color: slice.color,
|
|
408
|
-
borderColor: slice.color,
|
|
409
|
-
legendIndex: slice.legendIndex,
|
|
410
|
-
y: slice.data[0],
|
|
411
|
-
});
|
|
412
|
-
breakdown.unshift({
|
|
413
|
-
name: slice.name,
|
|
414
|
-
color: slice.color,
|
|
415
|
-
borderColor: slice.color,
|
|
416
|
-
y: slice.data[0],
|
|
417
|
-
});
|
|
418
|
-
} else {
|
|
419
|
-
useBreakdown = true;
|
|
420
|
-
let sum = 0;
|
|
421
|
-
let maxDecimal = 0;
|
|
422
|
-
for (let j = 0; j < slice.data.length; j++) {
|
|
423
|
-
const parts = slice.data[j].toString().split(".");
|
|
424
|
-
maxDecimal = Math.max(maxDecimal, parts[1] ? parts[1].length : 0);
|
|
425
|
-
sum += slice.data[j];
|
|
426
|
-
breakdown.unshift({
|
|
427
|
-
name: slice.name,
|
|
428
|
-
color: "rgba(0,0,0,0)",
|
|
429
|
-
borderColor: slice.color,
|
|
430
|
-
y: slice.data[j],
|
|
431
|
-
});
|
|
432
|
-
}
|
|
433
|
-
slices.unshift({
|
|
434
|
-
name: slice.name,
|
|
435
|
-
color: slice.color,
|
|
436
|
-
borderColor: slice.color,
|
|
437
|
-
legendIndex: slice.legendIndex,
|
|
438
|
-
y: parseFloat(sum.toFixed(maxDecimal)),
|
|
439
|
-
});
|
|
440
|
-
}
|
|
441
|
-
}
|
|
442
|
-
chart.tooltip = {
|
|
443
|
-
formatter: function () {
|
|
444
|
-
return this.key + ": " + this.y;
|
|
445
|
-
},
|
|
446
|
-
};
|
|
447
|
-
chart.plotOptions = {
|
|
448
|
-
pie: {
|
|
449
|
-
allowPointSelect: !useBreakdown,
|
|
450
|
-
cursor: useBreakdown ? null : "pointer",
|
|
451
|
-
shadow: false,
|
|
452
|
-
center: ["50%", "50%"],
|
|
453
|
-
dataLabels: {
|
|
454
|
-
enabled: false,
|
|
455
|
-
},
|
|
456
|
-
},
|
|
457
|
-
};
|
|
458
|
-
chart.series = [
|
|
459
|
-
{
|
|
460
|
-
name: " ",
|
|
461
|
-
data: slices,
|
|
462
|
-
showInLegend: true,
|
|
463
|
-
},
|
|
464
|
-
];
|
|
465
|
-
if (useBreakdown) {
|
|
466
|
-
chart.series.push({
|
|
467
|
-
name: " ",
|
|
468
|
-
data: breakdown,
|
|
469
|
-
innerSize: "90%",
|
|
470
|
-
showInLegend: false,
|
|
471
|
-
});
|
|
472
|
-
}
|
|
473
|
-
return chart;
|
|
474
|
-
};
|
|
475
|
-
}
|
|
476
|
-
}
|
|
477
|
-
const Pie = (...args) => new _Pie(...args);
|
|
478
|
-
|
|
479
|
-
pygal = {
|
|
480
|
-
...pygal,
|
|
481
|
-
Chart,
|
|
482
|
-
COLORS,
|
|
483
|
-
some,
|
|
484
|
-
Line,
|
|
485
|
-
StackedLine,
|
|
486
|
-
Bar,
|
|
487
|
-
StackedBar,
|
|
488
|
-
HorizontalBar,
|
|
489
|
-
StackedHorizontalBar,
|
|
490
|
-
XY,
|
|
491
|
-
Radar,
|
|
492
|
-
Pie,
|
|
493
|
-
};
|
|
494
|
-
|
|
495
|
-
globalThis.pygal = pygal;
|
|
1
|
+
/* global globalThis */
|
|
2
|
+
|
|
3
|
+
var pygal = {};
|
|
4
|
+
|
|
5
|
+
pygal.config = {
|
|
6
|
+
renderChart: (chart) => {
|
|
7
|
+
throw new Error(
|
|
8
|
+
"The config.renderChart function has not been set for pygal.",
|
|
9
|
+
);
|
|
10
|
+
},
|
|
11
|
+
availableWidth: 400,
|
|
12
|
+
availableHeight: 300,
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
const COLORS = [
|
|
16
|
+
[255, 89, 149],
|
|
17
|
+
[182, 227, 84],
|
|
18
|
+
[254, 237, 108],
|
|
19
|
+
[140, 237, 255],
|
|
20
|
+
[158, 111, 254],
|
|
21
|
+
[137, 156, 161],
|
|
22
|
+
[248, 248, 242],
|
|
23
|
+
[191, 70, 70],
|
|
24
|
+
[81, 96, 131],
|
|
25
|
+
[249, 38, 114],
|
|
26
|
+
[130, 180, 20],
|
|
27
|
+
[253, 151, 31],
|
|
28
|
+
[86, 194, 214],
|
|
29
|
+
[128, 131, 132],
|
|
30
|
+
[140, 84, 254],
|
|
31
|
+
[70, 84, 87],
|
|
32
|
+
];
|
|
33
|
+
|
|
34
|
+
const some = (val) => typeof val !== "undefined";
|
|
35
|
+
pygal.toJs = (val) => (val?.toJs ? val.toJs() : val);
|
|
36
|
+
|
|
37
|
+
class Chart {
|
|
38
|
+
constructor({
|
|
39
|
+
title,
|
|
40
|
+
width,
|
|
41
|
+
height,
|
|
42
|
+
range,
|
|
43
|
+
include_x_axis,
|
|
44
|
+
x_title,
|
|
45
|
+
y_title,
|
|
46
|
+
title_font_size,
|
|
47
|
+
fill,
|
|
48
|
+
stroke,
|
|
49
|
+
x_labels,
|
|
50
|
+
} = {}) {
|
|
51
|
+
const options = {};
|
|
52
|
+
if (some(title)) options.title = pygal.toJs(title);
|
|
53
|
+
if (some(width)) options.width = pygal.toJs(width);
|
|
54
|
+
if (some(height)) options.height = pygal.toJs(height);
|
|
55
|
+
if (some(range))
|
|
56
|
+
options.range = {
|
|
57
|
+
min: pygal.toJs(range)[0],
|
|
58
|
+
max: pygal.toJs(range)[1],
|
|
59
|
+
};
|
|
60
|
+
if (some(include_x_axis))
|
|
61
|
+
options.include_x_axis = pygal.toJs(include_x_axis);
|
|
62
|
+
if (some(x_title)) options.x_title = pygal.toJs(x_title);
|
|
63
|
+
if (some(y_title)) options.y_title = pygal.toJs(y_title);
|
|
64
|
+
if (some(title_font_size))
|
|
65
|
+
options.title_font_size = pygal.toJs(title_font_size);
|
|
66
|
+
if (some(fill)) options.fill = pygal.toJs(fill);
|
|
67
|
+
if (some(stroke)) options.stroke = pygal.toJs(stroke);
|
|
68
|
+
if (some(x_labels)) options.x_labels = pygal.toJs(x_labels);
|
|
69
|
+
|
|
70
|
+
this._options = options;
|
|
71
|
+
this._data = [];
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
add(label, values) {
|
|
75
|
+
if (!Array.isArray(pygal.toJs(values))) {
|
|
76
|
+
values = [values];
|
|
77
|
+
}
|
|
78
|
+
const data = [...pygal.toJs(values)].map((v) => v || 0);
|
|
79
|
+
|
|
80
|
+
this._data.unshift({
|
|
81
|
+
name: pygal.toJs(label),
|
|
82
|
+
color: this.#rgba(COLORS[this._data.length % COLORS.length], 0.75),
|
|
83
|
+
data: data,
|
|
84
|
+
marker: {
|
|
85
|
+
symbol: "circle",
|
|
86
|
+
},
|
|
87
|
+
stack: 1,
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
return "";
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
render() {
|
|
94
|
+
const options = this._options;
|
|
95
|
+
const title_style = {
|
|
96
|
+
color: "#FFFFFF",
|
|
97
|
+
};
|
|
98
|
+
if (options.title_font_size) {
|
|
99
|
+
title_style["font-size"] = options.title_font_size + "px";
|
|
100
|
+
}
|
|
101
|
+
const yPlotLines = [];
|
|
102
|
+
|
|
103
|
+
if (options.range) {
|
|
104
|
+
yPlotLines.push({
|
|
105
|
+
value: options.range.min,
|
|
106
|
+
width: 1,
|
|
107
|
+
color: "#FFFFFF",
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
const defaultWidth = pygal.config.availableWidth;
|
|
112
|
+
const defaultHeight = Math.min(defaultWidth, pygal.config.availableHeight);
|
|
113
|
+
|
|
114
|
+
let chart = {
|
|
115
|
+
chart: {
|
|
116
|
+
width: options.width || defaultWidth,
|
|
117
|
+
height: options.height || defaultHeight,
|
|
118
|
+
backgroundColor: "#000",
|
|
119
|
+
},
|
|
120
|
+
credits: {
|
|
121
|
+
enabled: false,
|
|
122
|
+
},
|
|
123
|
+
title: {
|
|
124
|
+
text: options.title,
|
|
125
|
+
style: title_style,
|
|
126
|
+
},
|
|
127
|
+
xAxis: {
|
|
128
|
+
title: {
|
|
129
|
+
text: options.x_title || null,
|
|
130
|
+
style: title_style,
|
|
131
|
+
margin: 20,
|
|
132
|
+
},
|
|
133
|
+
categories: options.x_labels,
|
|
134
|
+
labels: {
|
|
135
|
+
enabled: options.x_labels ? true : false,
|
|
136
|
+
},
|
|
137
|
+
tickLength: 0,
|
|
138
|
+
},
|
|
139
|
+
yAxis: {
|
|
140
|
+
startOnTick: false,
|
|
141
|
+
title: {
|
|
142
|
+
text: options.y_title || null,
|
|
143
|
+
style: title_style,
|
|
144
|
+
margin: 20,
|
|
145
|
+
},
|
|
146
|
+
plotLines: yPlotLines,
|
|
147
|
+
min: options.include_x_axis
|
|
148
|
+
? 0
|
|
149
|
+
: options.range
|
|
150
|
+
? options.range.min
|
|
151
|
+
: null,
|
|
152
|
+
max: options.range ? options.range.max : null,
|
|
153
|
+
gridLineDashStyle: "ShortDash",
|
|
154
|
+
gridLineColor: "#DDD",
|
|
155
|
+
tickLength: 0,
|
|
156
|
+
},
|
|
157
|
+
legend: {
|
|
158
|
+
itemStyle: {
|
|
159
|
+
color: "#FFFFFF",
|
|
160
|
+
},
|
|
161
|
+
layout: "vertical",
|
|
162
|
+
align: "left",
|
|
163
|
+
verticalAlign: "top",
|
|
164
|
+
y: 50,
|
|
165
|
+
borderWidth: 0,
|
|
166
|
+
},
|
|
167
|
+
labels: {
|
|
168
|
+
style: {
|
|
169
|
+
color: "#FFFFFF",
|
|
170
|
+
},
|
|
171
|
+
},
|
|
172
|
+
series: this._data,
|
|
173
|
+
};
|
|
174
|
+
|
|
175
|
+
for (let i = 0; i < chart.series.length; i++) {
|
|
176
|
+
chart.series[i].legendIndex = chart.series.length - i;
|
|
177
|
+
chart.series[i].index = chart.series.length - i;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
if (this.renderer) {
|
|
181
|
+
chart = this.renderer(options, chart);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
pygal.config.renderChart(chart);
|
|
185
|
+
|
|
186
|
+
return "";
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
get title() {
|
|
190
|
+
return this._options.title;
|
|
191
|
+
}
|
|
192
|
+
get width() {
|
|
193
|
+
return this._options.width;
|
|
194
|
+
}
|
|
195
|
+
get height() {
|
|
196
|
+
return this._options.height;
|
|
197
|
+
}
|
|
198
|
+
get range() {
|
|
199
|
+
return this._options.range;
|
|
200
|
+
}
|
|
201
|
+
get include_x_axis() {
|
|
202
|
+
return this._options.include_x_axis;
|
|
203
|
+
}
|
|
204
|
+
get x_title() {
|
|
205
|
+
return this._options.x_title;
|
|
206
|
+
}
|
|
207
|
+
get y_title() {
|
|
208
|
+
return this._options.y_title;
|
|
209
|
+
}
|
|
210
|
+
get title_font_size() {
|
|
211
|
+
return this._options.title_font_size;
|
|
212
|
+
}
|
|
213
|
+
get fill() {
|
|
214
|
+
return this._options.fill;
|
|
215
|
+
}
|
|
216
|
+
get stroke() {
|
|
217
|
+
return this._options.stroke;
|
|
218
|
+
}
|
|
219
|
+
get x_labels() {
|
|
220
|
+
return this._options.x_labels;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
set title(val) {
|
|
224
|
+
this._options.title = pygal.toJs(val);
|
|
225
|
+
}
|
|
226
|
+
set width(val) {
|
|
227
|
+
this._options.width = pygal.toJs(val);
|
|
228
|
+
}
|
|
229
|
+
set height(val) {
|
|
230
|
+
this._options.height = pygal.toJs(val);
|
|
231
|
+
}
|
|
232
|
+
set range(val) {
|
|
233
|
+
this._options.range = pygal.toJs(val);
|
|
234
|
+
}
|
|
235
|
+
set include_x_axis(val) {
|
|
236
|
+
this._options.include_x_axis = pygal.toJs(val);
|
|
237
|
+
}
|
|
238
|
+
set x_title(val) {
|
|
239
|
+
this._options.x_title = pygal.toJs(val);
|
|
240
|
+
}
|
|
241
|
+
set y_title(val) {
|
|
242
|
+
this._options.y_title = pygal.toJs(val);
|
|
243
|
+
}
|
|
244
|
+
set title_font_size(val) {
|
|
245
|
+
this._options.title_font_size = pygal.toJs(val);
|
|
246
|
+
}
|
|
247
|
+
set fill(val) {
|
|
248
|
+
this._options.fill = pygal.toJs(val);
|
|
249
|
+
}
|
|
250
|
+
set stroke(val) {
|
|
251
|
+
this._options.stroke = pygal.toJs(val);
|
|
252
|
+
}
|
|
253
|
+
set x_labels(val) {
|
|
254
|
+
this._options.x_labels = pygal.toJs(val);
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
#rgba(rgb, a) {
|
|
258
|
+
return "rgba(" + rgb.join(",") + "," + a + ")";
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
// Work around a webpack hot module reloading problem.
|
|
263
|
+
globalThis.$RefreshReg$ = () => {};
|
|
264
|
+
|
|
265
|
+
class _Line extends Chart {
|
|
266
|
+
constructor(...args) {
|
|
267
|
+
super(...args);
|
|
268
|
+
this.renderer = (options, chart) => {
|
|
269
|
+
chart.chart.type = pygal.toJs(options.fill) ? "area" : "line";
|
|
270
|
+
return chart;
|
|
271
|
+
};
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
const Line = (...args) => new _Line(...args);
|
|
275
|
+
|
|
276
|
+
class _StackedLine extends Chart {
|
|
277
|
+
constructor(...args) {
|
|
278
|
+
super(...args);
|
|
279
|
+
this.renderer = (options, chart) => {
|
|
280
|
+
chart.chart.type = pygal.toJs(options.fill) ? "area" : "line";
|
|
281
|
+
chart.plotOptions = {
|
|
282
|
+
area: {
|
|
283
|
+
stacking: "percent",
|
|
284
|
+
},
|
|
285
|
+
series: {
|
|
286
|
+
stacking: "percent",
|
|
287
|
+
},
|
|
288
|
+
};
|
|
289
|
+
return chart;
|
|
290
|
+
};
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
const StackedLine = (...args) => new _StackedLine(...args);
|
|
294
|
+
|
|
295
|
+
class _Bar extends Chart {
|
|
296
|
+
constructor(...args) {
|
|
297
|
+
super(...args);
|
|
298
|
+
this.renderer = (options, chart) => {
|
|
299
|
+
chart.chart.type = "column";
|
|
300
|
+
return chart;
|
|
301
|
+
};
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
const Bar = (...args) => new _Bar(...args);
|
|
305
|
+
|
|
306
|
+
class _StackedBar extends Chart {
|
|
307
|
+
constructor(...args) {
|
|
308
|
+
super(...args);
|
|
309
|
+
this.renderer = (options, chart) => {
|
|
310
|
+
chart.chart.type = "column";
|
|
311
|
+
chart.plotOptions = {
|
|
312
|
+
column: {
|
|
313
|
+
stacking: "percent",
|
|
314
|
+
},
|
|
315
|
+
};
|
|
316
|
+
return chart;
|
|
317
|
+
};
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
const StackedBar = (...args) => new _StackedBar(...args);
|
|
321
|
+
|
|
322
|
+
class _HorizontalBar extends Chart {
|
|
323
|
+
constructor(...args) {
|
|
324
|
+
super(...args);
|
|
325
|
+
this.renderer = (options, chart) => {
|
|
326
|
+
chart.chart.type = "bar";
|
|
327
|
+
return chart;
|
|
328
|
+
};
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
const HorizontalBar = (...args) => new _HorizontalBar(...args);
|
|
332
|
+
|
|
333
|
+
class _StackedHorizontalBar extends Chart {
|
|
334
|
+
constructor(...args) {
|
|
335
|
+
super(...args);
|
|
336
|
+
this.renderer = (options, chart) => {
|
|
337
|
+
chart.chart.type = "bar";
|
|
338
|
+
chart.plotOptions = {
|
|
339
|
+
bar: {
|
|
340
|
+
stacking: "percent",
|
|
341
|
+
},
|
|
342
|
+
};
|
|
343
|
+
return chart;
|
|
344
|
+
};
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
const StackedHorizontalBar = (...args) => new _StackedHorizontalBar(...args);
|
|
348
|
+
|
|
349
|
+
class _XY extends Chart {
|
|
350
|
+
constructor(...args) {
|
|
351
|
+
super(...args);
|
|
352
|
+
this.renderer = (options, chart) => {
|
|
353
|
+
if (pygal.toJs(options.stroke) === false) {
|
|
354
|
+
chart.chart.type = "scatter";
|
|
355
|
+
} else {
|
|
356
|
+
chart.chart.type = pygal.toJs(options.fill) ? "area" : "line";
|
|
357
|
+
}
|
|
358
|
+
chart.xAxis.labels.enabled = true;
|
|
359
|
+
|
|
360
|
+
return chart;
|
|
361
|
+
};
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
const XY = (...args) => new _XY(...args);
|
|
365
|
+
|
|
366
|
+
class _Radar extends Chart {
|
|
367
|
+
constructor(...args) {
|
|
368
|
+
super(...args);
|
|
369
|
+
this.renderer = (options, chart) => {
|
|
370
|
+
chart.chart.polar = true;
|
|
371
|
+
chart.chart.type = "line";
|
|
372
|
+
chart.xAxis = {
|
|
373
|
+
categories: pygal.toJs(options.x_labels),
|
|
374
|
+
tickmarkPlacement: "on",
|
|
375
|
+
lineWidth: 0,
|
|
376
|
+
};
|
|
377
|
+
chart.yAxis = {
|
|
378
|
+
gridLineInterpolation: "polygon",
|
|
379
|
+
lineWidth: 0,
|
|
380
|
+
min: 0,
|
|
381
|
+
gridLineDashStyle: "ShortDash",
|
|
382
|
+
gridLineColor: "#DDD",
|
|
383
|
+
};
|
|
384
|
+
for (let i = 0; i < chart.series.length; i++) {
|
|
385
|
+
chart.series[i].pointPlacement = "on";
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
return chart;
|
|
389
|
+
};
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
const Radar = (...args) => new _Radar(...args);
|
|
393
|
+
|
|
394
|
+
class _Pie extends Chart {
|
|
395
|
+
constructor(...args) {
|
|
396
|
+
super(...args);
|
|
397
|
+
this.renderer = (options, chart) => {
|
|
398
|
+
chart.chart.type = "pie";
|
|
399
|
+
const slices = [];
|
|
400
|
+
const breakdown = [];
|
|
401
|
+
let useBreakdown = false;
|
|
402
|
+
for (let i = 0; i < chart.series.length; i++) {
|
|
403
|
+
const slice = chart.series[i];
|
|
404
|
+
if (slice.data.length === 1) {
|
|
405
|
+
slices.unshift({
|
|
406
|
+
name: slice.name,
|
|
407
|
+
color: slice.color,
|
|
408
|
+
borderColor: slice.color,
|
|
409
|
+
legendIndex: slice.legendIndex,
|
|
410
|
+
y: slice.data[0],
|
|
411
|
+
});
|
|
412
|
+
breakdown.unshift({
|
|
413
|
+
name: slice.name,
|
|
414
|
+
color: slice.color,
|
|
415
|
+
borderColor: slice.color,
|
|
416
|
+
y: slice.data[0],
|
|
417
|
+
});
|
|
418
|
+
} else {
|
|
419
|
+
useBreakdown = true;
|
|
420
|
+
let sum = 0;
|
|
421
|
+
let maxDecimal = 0;
|
|
422
|
+
for (let j = 0; j < slice.data.length; j++) {
|
|
423
|
+
const parts = slice.data[j].toString().split(".");
|
|
424
|
+
maxDecimal = Math.max(maxDecimal, parts[1] ? parts[1].length : 0);
|
|
425
|
+
sum += slice.data[j];
|
|
426
|
+
breakdown.unshift({
|
|
427
|
+
name: slice.name,
|
|
428
|
+
color: "rgba(0,0,0,0)",
|
|
429
|
+
borderColor: slice.color,
|
|
430
|
+
y: slice.data[j],
|
|
431
|
+
});
|
|
432
|
+
}
|
|
433
|
+
slices.unshift({
|
|
434
|
+
name: slice.name,
|
|
435
|
+
color: slice.color,
|
|
436
|
+
borderColor: slice.color,
|
|
437
|
+
legendIndex: slice.legendIndex,
|
|
438
|
+
y: parseFloat(sum.toFixed(maxDecimal)),
|
|
439
|
+
});
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
chart.tooltip = {
|
|
443
|
+
formatter: function () {
|
|
444
|
+
return this.key + ": " + this.y;
|
|
445
|
+
},
|
|
446
|
+
};
|
|
447
|
+
chart.plotOptions = {
|
|
448
|
+
pie: {
|
|
449
|
+
allowPointSelect: !useBreakdown,
|
|
450
|
+
cursor: useBreakdown ? null : "pointer",
|
|
451
|
+
shadow: false,
|
|
452
|
+
center: ["50%", "50%"],
|
|
453
|
+
dataLabels: {
|
|
454
|
+
enabled: false,
|
|
455
|
+
},
|
|
456
|
+
},
|
|
457
|
+
};
|
|
458
|
+
chart.series = [
|
|
459
|
+
{
|
|
460
|
+
name: " ",
|
|
461
|
+
data: slices,
|
|
462
|
+
showInLegend: true,
|
|
463
|
+
},
|
|
464
|
+
];
|
|
465
|
+
if (useBreakdown) {
|
|
466
|
+
chart.series.push({
|
|
467
|
+
name: " ",
|
|
468
|
+
data: breakdown,
|
|
469
|
+
innerSize: "90%",
|
|
470
|
+
showInLegend: false,
|
|
471
|
+
});
|
|
472
|
+
}
|
|
473
|
+
return chart;
|
|
474
|
+
};
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
const Pie = (...args) => new _Pie(...args);
|
|
478
|
+
|
|
479
|
+
pygal = {
|
|
480
|
+
...pygal,
|
|
481
|
+
Chart,
|
|
482
|
+
COLORS,
|
|
483
|
+
some,
|
|
484
|
+
Line,
|
|
485
|
+
StackedLine,
|
|
486
|
+
Bar,
|
|
487
|
+
StackedBar,
|
|
488
|
+
HorizontalBar,
|
|
489
|
+
StackedHorizontalBar,
|
|
490
|
+
XY,
|
|
491
|
+
Radar,
|
|
492
|
+
Pie,
|
|
493
|
+
};
|
|
494
|
+
|
|
495
|
+
globalThis.pygal = pygal;
|