bezel-charts 1.4.0 → 1.6.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.
@@ -1,4 +1,4 @@
1
- /*! Bezel Charts v1.4.0 | MIT | github.com/ShazMoghaddam/bezel-charts */
1
+ /*! Bezel Charts v1.6.0 | MIT | github.com/ShazMoghaddam/bezel-charts */
2
2
 
3
3
  // src/core/util.js
4
4
  var SANS = "ui-sans-serif,system-ui,-apple-system,'Segoe UI',Roboto,Helvetica,Arial,sans-serif";
@@ -268,7 +268,7 @@ var THEMES = {
268
268
  };
269
269
 
270
270
  // src/render.js
271
- var NAMES = ["spark", "line", "area", "bars", "scatter", "ring", "donut", "gauge", "progress", "heatmap"];
271
+ var NAMES = ["spark", "line", "area", "bars", "histogram", "boxplot", "scatter", "ring", "donut", "gauge", "progress", "heatmap"];
272
272
  var TYPES = {};
273
273
  function register(type, fn) {
274
274
  TYPES[type] = fn;
@@ -346,7 +346,12 @@ var ATTRIBUTES = [
346
346
  "angle-labels",
347
347
  "dash",
348
348
  "markers",
349
- "patterns"
349
+ "patterns",
350
+ "bins",
351
+ "bin-width",
352
+ "mark",
353
+ "percent",
354
+ "whiskers"
350
355
  ];
351
356
  var HOST_CSS = `:host{display:block;position:relative;max-width:100%}:host([hidden]){display:none}svg{display:block;max-width:100%;height:auto;overflow:visible}.tip{position:absolute;left:0;top:0;pointer-events:none;background:#0b0b10;color:#f2f1f7;font:600 12px/1.5 ${MONO};padding:7px 10px;border-radius:10px;white-space:pre;opacity:0;transform:translate(-50%,calc(-100% - 12px));transition:opacity .12s;z-index:3;border:1px solid #2a2935;box-shadow:0 8px 24px rgba(0,0,0,.35)}.tip.on{opacity:1}.c{outline:none}.c:focus-visible{outline:2px solid #fff;outline-offset:3px;box-shadow:0 0 0 7px #000}.k{stroke:currentColor;stroke-width:2;stroke-opacity:1}.sr{position:absolute;width:1px;height:1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap}@media (forced-colors:active){.c:focus-visible{outline-color:Highlight}}`;
352
357
  var STEPS = { ArrowLeft: -1, ArrowUp: -1, ArrowRight: 1, ArrowDown: 1 };
@@ -635,7 +640,7 @@ function axisWidth(ticks) {
635
640
  return tw(t, 10, true);
636
641
  })) + 10;
637
642
  }
638
- function seriesTable(o, total) {
643
+ function seriesTable(o, total2) {
639
644
  var S = series(o.values), names = list(o.series), labels = list(o.labels), rows = [];
640
645
  var n = Math.max.apply(null, [0].concat(S.map(function(s) {
641
646
  return s.length;
@@ -646,13 +651,13 @@ function seriesTable(o, total) {
646
651
  row.push(i < s.length ? fmt(s[i], o) : "");
647
652
  t += i < s.length ? s[i] : 0;
648
653
  });
649
- if (total) row.push(fmt(t, o));
654
+ if (total2) row.push(fmt(t, o));
650
655
  rows.push(row);
651
656
  }
652
657
  var head = S.length > 1 || names.length ? S.map(function(_, k) {
653
658
  return names[k] || "Series " + (k + 1);
654
659
  }) : ["Value"];
655
- return { head: ["Label"].concat(head, total ? ["Total"] : []), rows };
660
+ return { head: ["Label"].concat(head, total2 ? ["Total"] : []), rows };
656
661
  }
657
662
 
658
663
  // src/core/xy.js
@@ -1164,8 +1169,348 @@ bars.table = function(o) {
1164
1169
  register("bars", bars);
1165
1170
  define("bars");
1166
1171
 
1172
+ // src/charts/histogram.js
1173
+ function histogram(o, th) {
1174
+ var b = binned(o), names = list(o.series), pal = palette(o, th), h = num(o.height, 190);
1175
+ var S = b ? b.S : [], k = S.length, multi = k > 1 || names.length > 0, pct = bool(o.percent);
1176
+ var nameOf = function(j) {
1177
+ return names[j] || "Series " + (j + 1);
1178
+ };
1179
+ var eo = Object.assign({}, o, { decimals: has(o.decimals) ? o.decimals : b ? b.dp : 0 });
1180
+ var range = function(i2) {
1181
+ return fmt(b.edge(i2), eo) + " to " + fmt(b.edge(i2 + 1), eo);
1182
+ };
1183
+ var share = function(j, i2) {
1184
+ return Math.round(b.counts[j][i2] / S[j].length * 100);
1185
+ };
1186
+ var height = function(j, i2) {
1187
+ return pct ? b.counts[j][i2] / S[j].length * 100 : b.counts[j][i2];
1188
+ };
1189
+ var marks = list(o.mark).filter(function(m) {
1190
+ return m === "mean" || m === "median";
1191
+ });
1192
+ var patOf = k > 1 ? styleOf(o.patterns, PATTERNS, "solid") : null, defs = "", fills = [];
1193
+ for (var q = 0; patOf && q < k; q++) {
1194
+ if (patOf(q) === "solid") continue;
1195
+ var pid = newId("g");
1196
+ defs += pattern(pid, patOf(q), pal[q % pal.length], o.background || th.tile);
1197
+ fills[q] = "url(#" + pid + ")";
1198
+ }
1199
+ var key = patOf && function(j, x, y) {
1200
+ return '<rect x="' + r2(x) + '" y="' + r2(y + 1) + '" width="10" height="10" rx="2" fill="' + (fills[j] || pal[j % pal.length]) + '"/>';
1201
+ };
1202
+ var peak = 0, n = 0;
1203
+ if (b) {
1204
+ for (var i = 0; i < b.count; i++) if (total(b, i) > total(b, peak)) peak = i;
1205
+ S.forEach(function(s) {
1206
+ n += s.length;
1207
+ });
1208
+ }
1209
+ return tile(o, th, h, function(x0, y0, w, h2) {
1210
+ if (!b) return emptyState(th, x0, y0, w, h2);
1211
+ var s = defs ? "<defs>" + defs + "</defs>" : "", top = y0;
1212
+ if (multi) {
1213
+ var lg = legend(S.map(function(_, j) {
1214
+ return nameOf(j);
1215
+ }), pal, th, x0, top, w, key, key && 15);
1216
+ s += lg.svg;
1217
+ top += lg.height;
1218
+ }
1219
+ var most = 0;
1220
+ S.forEach(function(_, j) {
1221
+ for (var i2 = 0; i2 < b.count; i2++) most = Math.max(most, height(j, i2));
1222
+ });
1223
+ var sc = niceScale(0, most || 1, 4);
1224
+ var tl = sc.ticks.map(function(t) {
1225
+ return fmt(t, { lang: o.lang }, true) + (pct ? "%" : "");
1226
+ });
1227
+ var axisW = Math.max.apply(null, tl.map(function(t) {
1228
+ return tw(t, 10, true);
1229
+ })) + 10;
1230
+ var px = x0 + axisW, pw = w - axisW, ph = h2 - (top - y0) - 20, cw = pw / b.count;
1231
+ var X = function(i2) {
1232
+ return px + i2 * cw;
1233
+ };
1234
+ var Y = function(v) {
1235
+ return top + ph - (v - sc.lo) / (sc.hi - sc.lo) * ph;
1236
+ };
1237
+ sc.ticks.forEach(function(t, i2) {
1238
+ var y = Y(t);
1239
+ s += '<line x1="' + r2(px) + '" x2="' + r2(px + pw) + '" y1="' + r2(y) + '" y2="' + r2(y) + '" stroke="' + th.grid + '"' + (t === 0 ? "" : ' stroke-dasharray="2 4"') + "/>" + text(px - 8, y + 3.5, tl[i2], small(th, 10, 'text-anchor="end"'));
1240
+ });
1241
+ var el = [];
1242
+ for (var e = 0; e <= b.count; e++) el.push(fmt(b.edge(e), eo, true));
1243
+ var every = Math.max(1, Math.ceil((Math.max.apply(null, el.map(function(l) {
1244
+ return tw(l, 10, true);
1245
+ })) * 1.5 + 8) / cw));
1246
+ for (e = 0; e <= b.count; e += every) {
1247
+ s += text(X(e), top + ph + 15, el[e], small(th, 10, 'text-anchor="' + (e === 0 ? "start" : e === b.count ? "end" : "middle") + '"'));
1248
+ }
1249
+ S.forEach(function(_, j) {
1250
+ for (var i2 = 0; i2 < b.count; i2++) {
1251
+ var v = height(j, i2);
1252
+ if (!v) continue;
1253
+ var y = Y(v);
1254
+ s += '<rect x="' + r2(X(i2) + 0.5) + '" y="' + r2(y) + '" width="' + r2(Math.max(1, cw - 1)) + '" height="' + r2(top + ph - y) + '" fill="' + (fills[j] || pal[j % pal.length]) + '"' + (multi ? ' fill-opacity=".55"' : "") + anim(o, "bzc-g", Math.min(0.6, i2 * 0.03)) + "/>";
1255
+ }
1256
+ });
1257
+ var lo = b.edge(0), span = b.edge(b.count) - lo, lines = [];
1258
+ S.forEach(function(ser, j) {
1259
+ marks.forEach(function(m) {
1260
+ var v = m === "mean" ? mean(ser) : median(ser);
1261
+ lines.push({ x: px + (v - lo) / span * pw, c: multi ? pal[j % pal.length] : th.fg, t: (multi ? nameOf(j) + " " : "") + m + " " + fmt(v, o) });
1262
+ });
1263
+ });
1264
+ if (lines.length) {
1265
+ var xs = lines.map(function(l) {
1266
+ return l.x;
1267
+ }), left = (Math.min.apply(null, xs) + Math.max.apply(null, xs)) / 2 > px + pw / 2;
1268
+ var lx = left ? Math.min.apply(null, xs) - 5 : Math.max.apply(null, xs) + 5;
1269
+ lines.forEach(function(l, r) {
1270
+ s += '<line x1="' + r2(l.x) + '" x2="' + r2(l.x) + '" y1="' + r2(top) + '" y2="' + r2(top + ph) + '" stroke="' + l.c + '" stroke-width="1.5" stroke-dasharray="4 3"/>' + text(lx, top + 9 + r * 12, l.t, small(th, 10, 'text-anchor="' + (left ? "end" : "start") + '"', multi ? l.c : th.fg));
1271
+ });
1272
+ }
1273
+ for (i = 0; i < b.count; i++) {
1274
+ var tip = range(i);
1275
+ S.forEach(function(_, j) {
1276
+ tip += "\n" + (multi ? nameOf(j) + ": " : "") + b.counts[j][i] + " (" + share(j, i) + "%)";
1277
+ });
1278
+ s += hit(X(i), top, cw, ph, tip);
1279
+ }
1280
+ return s;
1281
+ }, {
1282
+ summary: b ? (multi ? k + " series, " : "") + n + " values in " + b.count + " ranges from " + fmt(b.edge(0), eo) + " to " + fmt(b.edge(b.count), eo) + ", most in " + range(peak) : "no data"
1283
+ });
1284
+ }
1285
+ histogram.table = function(o) {
1286
+ var b = binned(o), names = list(o.series);
1287
+ if (!b) return { head: ["Range", "Count"], rows: [] };
1288
+ var multi = b.S.length > 1 || names.length > 0, eo = Object.assign({}, o, { decimals: has(o.decimals) ? o.decimals : b.dp }), rows = [];
1289
+ for (var i = 0; i < b.count; i++) {
1290
+ var row = [fmt(b.edge(i), eo) + " to " + fmt(b.edge(i + 1), eo)];
1291
+ if (multi) b.S.forEach(function(_, j) {
1292
+ row.push(String(b.counts[j][i]));
1293
+ });
1294
+ else row.push(String(b.counts[0][i]), Math.round(b.counts[0][i] / b.S[0].length * 100) + "%");
1295
+ rows.push(row);
1296
+ }
1297
+ return { head: ["Range"].concat(multi ? b.S.map(function(_, j) {
1298
+ return names[j] || "Series " + (j + 1);
1299
+ }) : ["Count", "Share"]), rows };
1300
+ };
1301
+ function niceWidth(raw) {
1302
+ var e = Math.floor(Math.log10(raw)), p = Number("1e" + e), f = raw / p;
1303
+ var m = f < 1.4142 ? 1 : f < 2.2361 ? 2 : f < 3.5355 ? 2.5 : f < 7.0711 ? 5 : 10;
1304
+ return { w: m * p, dp: Math.max(0, m === 10 ? -e - 1 : -e) + (m === 2.5 ? 1 : 0) };
1305
+ }
1306
+ function binned(o) {
1307
+ var S = series(o.values), all = [].concat.apply([], S);
1308
+ if (!all.length) return null;
1309
+ var lo = Math.min.apply(null, all), hi = Math.max.apply(null, all), w = num(o.binWidth, 0), dp, nice;
1310
+ if (w > 0 && (hi - lo) / w <= 200) {
1311
+ var str = String(o.binWidth), dot = str.indexOf(".");
1312
+ dp = dot < 0 ? 0 : Math.min(6, str.length - dot - 1);
1313
+ } else {
1314
+ var k = num(o.bins, 0) > 0 ? Math.round(num(o.bins, 0)) : Math.ceil(Math.log2(all.length) + 1);
1315
+ k = Math.min(Math.max(k, 1), 50);
1316
+ nice = niceWidth(hi > lo ? (hi - lo) / k : Math.abs(lo) || 1);
1317
+ w = nice.w;
1318
+ dp = nice.dp;
1319
+ }
1320
+ var s0 = Math.floor(lo / w);
1321
+ var edge = function(i) {
1322
+ return Number(((s0 + i) * w).toFixed(dp + 3));
1323
+ };
1324
+ while (edge(0) > lo) s0--;
1325
+ var count = Math.max(1, Math.ceil((hi - edge(0)) / w));
1326
+ while (count > 1 && edge(count - 1) >= hi) count--;
1327
+ while (edge(count) < hi) count++;
1328
+ var counts = S.map(function(ser) {
1329
+ var c = [];
1330
+ for (var i = 0; i < count; i++) c.push(0);
1331
+ ser.forEach(function(x) {
1332
+ var i2 = Math.min(count - 1, Math.max(0, Math.floor((x - edge(0)) / w)));
1333
+ while (i2 > 0 && x < edge(i2)) i2--;
1334
+ while (i2 < count - 1 && x >= edge(i2 + 1)) i2++;
1335
+ c[i2]++;
1336
+ });
1337
+ return c;
1338
+ });
1339
+ return { S, edge, count, counts, dp };
1340
+ }
1341
+ function total(b, i) {
1342
+ var t = 0;
1343
+ b.counts.forEach(function(c) {
1344
+ t += c[i];
1345
+ });
1346
+ return t;
1347
+ }
1348
+ function mean(v) {
1349
+ var t = 0;
1350
+ v.forEach(function(x) {
1351
+ t += x;
1352
+ });
1353
+ return t / v.length;
1354
+ }
1355
+ function median(v) {
1356
+ var s = v.slice().sort(function(a, b) {
1357
+ return a - b;
1358
+ }), m = Math.floor(s.length / 2);
1359
+ return s.length % 2 ? s[m] : (s[m - 1] + s[m]) / 2;
1360
+ }
1361
+
1362
+ // src/entries/histogram.js
1363
+ register("histogram", histogram);
1364
+ define("histogram");
1365
+
1366
+ // src/charts/boxplot.js
1367
+ function boxplot(o, th) {
1368
+ var S = series(o.values), names = list(o.series), pal = palette(o, th), k = S.length;
1369
+ var horiz = bool(o.horizontal), many = list(o.color).length > 1, showMean = list(o.mark).indexOf("mean") >= 0;
1370
+ var stats = S.map(function(v) {
1371
+ return summary(v, o.whiskers === "range");
1372
+ });
1373
+ var nameOf = function(i) {
1374
+ return names[i] || "Group " + (i + 1);
1375
+ };
1376
+ var h = num(o.height, horiz ? Math.max(120, k * 36 + 24) : 200);
1377
+ var f = function(v) {
1378
+ return fmt(v, o);
1379
+ };
1380
+ var meds = stats.map(function(s) {
1381
+ return s.median;
1382
+ });
1383
+ var about = k === 1 ? "median " + f(stats[0].median) + ", middle half " + f(stats[0].q1) + " to " + f(stats[0].q3) : k + " groups, medians from " + f(Math.min.apply(null, meds)) + " to " + f(Math.max.apply(null, meds));
1384
+ return tile(o, th, h, function(x0, y0, w, h2) {
1385
+ if (!k) return emptyState(th, x0, y0, w, h2);
1386
+ var lo = Math.min.apply(null, stats.map(function(s2) {
1387
+ return s2.min;
1388
+ })), hi = Math.max.apply(null, stats.map(function(s2) {
1389
+ return s2.max;
1390
+ }));
1391
+ if (has(o.goal)) {
1392
+ lo = Math.min(lo, +o.goal);
1393
+ hi = Math.max(hi, +o.goal);
1394
+ }
1395
+ var sc = niceScale(lo, hi, 4), s = "";
1396
+ var tl = sc.ticks.map(function(t) {
1397
+ return fmt(t, o, true);
1398
+ });
1399
+ var nameW = horiz ? Math.min(w * 0.4, Math.max.apply(null, S.map(function(_, i) {
1400
+ return tw(nameOf(i), 11);
1401
+ })) + 12) : 0;
1402
+ var axisW = horiz ? 0 : Math.max.apply(null, tl.map(function(t) {
1403
+ return tw(t, 10, true);
1404
+ })) + 10;
1405
+ var px = x0 + (horiz ? nameW : axisW), pw = w - (horiz ? nameW : axisW), ph = h2 - 20;
1406
+ var V = horiz ? function(v) {
1407
+ return px + (v - sc.lo) / (sc.hi - sc.lo) * pw;
1408
+ } : function(v) {
1409
+ return y0 + ph - (v - sc.lo) / (sc.hi - sc.lo) * ph;
1410
+ };
1411
+ var band = (horiz ? ph : pw) / k, half = Math.min(28, band * 0.28);
1412
+ var C = function(i) {
1413
+ return (horiz ? y0 : px) + band * (i + 0.5);
1414
+ };
1415
+ var P = function(c, v) {
1416
+ return horiz ? [v, c] : [c, v];
1417
+ };
1418
+ var seg = function(c1, v1, c2, v2, attrs) {
1419
+ var a = P(c1, v1), b = P(c2, v2);
1420
+ return '<line x1="' + r2(a[0]) + '" y1="' + r2(a[1]) + '" x2="' + r2(b[0]) + '" y2="' + r2(b[1]) + '"' + attrs + "/>";
1421
+ };
1422
+ sc.ticks.forEach(function(t, i) {
1423
+ var v = V(t);
1424
+ s += seg(horiz ? y0 : px, v, horiz ? y0 + ph : px + pw, v, ' stroke="' + th.grid + '"' + (t === 0 ? "" : ' stroke-dasharray="2 4"')) + (horiz ? text(v, y0 + ph + 15, tl[i], small(th, 10, 'text-anchor="middle"')) : text(px - 8, v + 3.5, tl[i], small(th, 10, 'text-anchor="end"')));
1425
+ });
1426
+ stats.forEach(function(st, i) {
1427
+ var c = C(i), col = many ? pal[i % pal.length] : pal[0], line2 = ' stroke="' + col + '" stroke-width="1.5"';
1428
+ if (k > 1 || names.length) {
1429
+ var label = fit(nameOf(i), horiz ? nameW - 10 : band - 6, horiz ? 11 : 10, !horiz);
1430
+ s += horiz ? text(x0, c + 4, label, small(th, 11, "", th.fg)) : text(c, y0 + ph + 15, label, small(th, 10, 'text-anchor="middle"'));
1431
+ }
1432
+ if (!st.n) return;
1433
+ var a1 = P(c - half, V(st.q1)), a2 = P(c + half, V(st.q3));
1434
+ s += "<g" + anim(o, "bzc-a", Math.min(0.6, i * 0.06)) + ">" + seg(c, V(st.low), c, V(st.q1), line2) + seg(c, V(st.q3), c, V(st.high), line2) + seg(c - half / 2, V(st.low), c + half / 2, V(st.low), line2) + seg(c - half / 2, V(st.high), c + half / 2, V(st.high), line2) + '<rect x="' + r2(Math.min(a1[0], a2[0])) + '" y="' + r2(Math.min(a1[1], a2[1])) + '" width="' + r2(Math.abs(a2[0] - a1[0])) + '" height="' + r2(Math.max(1, Math.abs(a2[1] - a1[1]))) + '" rx="3" fill="' + col + '" fill-opacity=".22"' + line2 + "/>" + seg(c - half, V(st.median), c + half, V(st.median), ' stroke="' + col + '" stroke-width="2.5"');
1435
+ st.outliers.forEach(function(v) {
1436
+ var p = P(c, V(v));
1437
+ s += '<circle cx="' + r2(p[0]) + '" cy="' + r2(p[1]) + '" r="2.5" fill="none"' + line2 + "/>";
1438
+ });
1439
+ if (showMean) {
1440
+ var m = P(c, V(st.mean));
1441
+ s += marker("diamond", m[0], m[1], 4, ' fill="' + (o.background || th.tile) + '"' + line2);
1442
+ }
1443
+ s += "</g>";
1444
+ });
1445
+ if (has(o.goal)) {
1446
+ var g = V(+o.goal);
1447
+ s += horiz ? seg(g, y0, g, y0 + ph, ' stroke="' + th.fg + '" stroke-opacity=".55" stroke-dasharray="4 4"') : goalLine(o, th, px, px + pw, g);
1448
+ }
1449
+ stats.forEach(function(st, i) {
1450
+ if (!st.n) return;
1451
+ var tip = nameOf(i) + "\nMedian " + f(st.median) + "\nMiddle half " + f(st.q1) + " to " + f(st.q3) + "\n" + (st.outliers.length ? "Range without outliers " : "Range ") + f(st.low) + " to " + f(st.high) + (st.outliers.length ? "\n" + st.outliers.length + (st.outliers.length === 1 ? " outlier" : " outliers") : "") + (showMean ? "\nMean " + f(st.mean) : "") + "\nn = " + st.n;
1452
+ s += horiz ? hit(px, C(i) - band / 2, pw, band, tip) : hit(C(i) - band / 2, y0, band, ph, tip);
1453
+ });
1454
+ return s;
1455
+ }, { summary: k ? about : "no data" });
1456
+ }
1457
+ boxplot.table = function(o) {
1458
+ var S = series(o.values), names = list(o.series), showMean = list(o.mark).indexOf("mean") >= 0;
1459
+ var f = function(v) {
1460
+ return fmt(v, o);
1461
+ };
1462
+ return {
1463
+ head: ["Group", "Count", "Lowest", "Lower quartile", "Median", "Upper quartile", "Highest", "Outliers"].concat(showMean ? ["Mean"] : []),
1464
+ rows: S.map(function(v, i) {
1465
+ var st = summary(v, o.whiskers === "range");
1466
+ return [names[i] || "Group " + (i + 1), String(st.n), f(st.min), f(st.q1), f(st.median), f(st.q3), f(st.max), String(st.outliers.length)].concat(showMean ? [f(st.mean)] : []);
1467
+ })
1468
+ };
1469
+ };
1470
+ function fit(name, width, size, mono) {
1471
+ var t = String(name);
1472
+ while (t.length > 1 && tw(t, size, mono) > width) t = trunc(t, t.length - 1);
1473
+ return t;
1474
+ }
1475
+ function quantile(s, p) {
1476
+ var h = (s.length - 1) * p, i = Math.floor(h);
1477
+ return i + 1 < s.length ? s[i] + (h - i) * (s[i + 1] - s[i]) : s[i];
1478
+ }
1479
+ function summary(v, range) {
1480
+ var s = v.slice().sort(function(a, b) {
1481
+ return a - b;
1482
+ }), n = s.length;
1483
+ if (!n) return { n: 0, outliers: [] };
1484
+ var q1 = quantile(s, 0.25), q3 = quantile(s, 0.75), iqr = q3 - q1, t = 0;
1485
+ var lowFence = range ? -Infinity : q1 - 1.5 * iqr, highFence = range ? Infinity : q3 + 1.5 * iqr;
1486
+ var inside = s.filter(function(x) {
1487
+ return x >= lowFence && x <= highFence;
1488
+ });
1489
+ s.forEach(function(x) {
1490
+ t += x;
1491
+ });
1492
+ return {
1493
+ n,
1494
+ min: s[0],
1495
+ max: s[n - 1],
1496
+ q1,
1497
+ median: quantile(s, 0.5),
1498
+ q3,
1499
+ mean: t / n,
1500
+ low: inside[0],
1501
+ high: inside[inside.length - 1],
1502
+ outliers: s.filter(function(x) {
1503
+ return x < lowFence || x > highFence;
1504
+ })
1505
+ };
1506
+ }
1507
+
1508
+ // src/entries/boxplot.js
1509
+ register("boxplot", boxplot);
1510
+ define("boxplot");
1511
+
1167
1512
  // src/charts/scatter.js
1168
- function fit(xs, ys) {
1513
+ function fit2(xs, ys) {
1169
1514
  var n = Math.min(xs.length, ys.length);
1170
1515
  if (n < 2) return null;
1171
1516
  var mx = 0, my = 0, i;
@@ -1270,7 +1615,7 @@ function scatter(o, th) {
1270
1615
  if (has(o.goal)) s += goalLine(o, th, px, px + pw, PY(+o.goal));
1271
1616
  if (trend) {
1272
1617
  groups.forEach(function(gr, j) {
1273
- var f = fit(gr.xs, gr.ys);
1618
+ var f = fit2(gr.xs, gr.ys);
1274
1619
  if (!f) return;
1275
1620
  var xa = Math.min.apply(null, gr.xs), xb = Math.max.apply(null, gr.xs);
1276
1621
  var ya = f.slope * xa + f.intercept, yb = f.slope * xb + f.intercept;
@@ -1395,43 +1740,43 @@ function donut(o, th) {
1395
1740
  })));
1396
1741
  labels.push("Other");
1397
1742
  }
1398
- var total = sum(v), h = num(o.height, 150);
1743
+ var total2 = sum(v), h = num(o.height, 150);
1399
1744
  var st = statOf(v, o, "");
1400
1745
  return tile(o, th, h, function(x0, y0, w, h2) {
1401
- if (!total) return emptyState(th, x0, y0, w, h2);
1746
+ if (!total2) return emptyState(th, x0, y0, w, h2);
1402
1747
  var s = "", size = Math.min(h2, w * 0.5), cx = x0 + size / 2, cy = y0 + h2 / 2;
1403
1748
  var sw = size * 0.16, r = (size - sw) / 2, start = 0, gap = v.filter(Boolean).length > 1 ? 0.9 : 0;
1404
1749
  v.forEach(function(n, i) {
1405
- var len = n / total * 100;
1750
+ var len = n / total2 * 100;
1406
1751
  if (len <= 0) return;
1407
1752
  var seg = Math.max(0.01, len - gap);
1408
1753
  s += '<circle cx="' + r2(cx) + '" cy="' + r2(cy) + '" r="' + r2(r) + '" fill="none" stroke="' + pal[i % pal.length] + '" stroke-width="' + r2(sw) + '" pathLength="100" stroke-dasharray="' + r2(seg) + " " + r2(100 - seg) + '" stroke-dashoffset="' + r2(-start) + '" transform="rotate(-90 ' + r2(cx) + " " + r2(cy) + ')"' + anim(o, "bzc-a", i * 0.08) + "/>";
1409
1754
  start += len;
1410
1755
  });
1411
- s += text(cx, cy + 2, fmt(total, o, true), 'text-anchor="middle" fill="' + th.fg + '" font-family="' + SANS + '" font-size="' + r2(size * 0.17) + '" font-weight="800"');
1756
+ s += text(cx, cy + 2, fmt(total2, o, true), 'text-anchor="middle" fill="' + th.fg + '" font-family="' + SANS + '" font-size="' + r2(size * 0.17) + '" font-weight="800"');
1412
1757
  s += text(cx, cy + 2 + 14, (has(o.centerLabel) ? o.centerLabel : "Total").toUpperCase(), small(th, 9, 'text-anchor="middle" letter-spacing="1"'));
1413
1758
  var lx = x0 + size + 22, rowH = Math.min(24, h2 / v.length), ly = cy - rowH * v.length / 2;
1414
1759
  v.forEach(function(n, i) {
1415
- var y = ly + i * rowH + rowH / 2, pct = Math.round(n / total * 100);
1760
+ var y = ly + i * rowH + rowH / 2, pct = Math.round(n / total2 * 100);
1416
1761
  var tip = (labels[i] || "#" + (i + 1)) + ": " + fmt(n, o) + " (" + pct + "%)";
1417
1762
  s += '<circle cx="' + r2(lx + 4) + '" cy="' + r2(y) + '" r="4" fill="' + pal[i % pal.length] + '"/>' + text(lx + 14, y + 4, trunc(labels[i] || "#" + (i + 1), Math.floor((x0 + w - lx - 50) / 6.7)), 'fill="' + th.fg + '" font-family="' + SANS + '" font-size="12"') + text(x0 + w, y + 4, pct + "%", 'text-anchor="end" fill="' + th.muted + '" font-family="' + MONO + '" font-size="11" font-weight="600"') + hit(lx, y - rowH / 2, x0 + w - lx, rowH, tip);
1418
1763
  });
1419
1764
  start = 0;
1420
1765
  v.forEach(function(n, i) {
1421
- var len = n / total * 100;
1766
+ var len = n / total2 * 100;
1422
1767
  if (len <= 0) return;
1423
1768
  s += '<circle cx="' + r2(cx) + '" cy="' + r2(cy) + '" r="' + r2(r) + '" fill="none" stroke="#000" stroke-opacity="0" stroke-width="' + r2(sw) + '" pathLength="100" stroke-dasharray="' + r2(len) + " " + r2(100 - len) + '" stroke-dashoffset="' + r2(-start) + '" transform="rotate(-90 ' + r2(cx) + " " + r2(cy) + ')" class="bzc-hit" data-skip="" data-tip="' + esc((labels[i] || "#" + (i + 1)) + ": " + fmt(n, o) + " (" + Math.round(len) + "%)") + '"/>';
1424
1769
  start += len;
1425
1770
  });
1426
1771
  return s;
1427
- }, { stat: st, summary: "total " + fmt(total, o) + " across " + v.length + " parts" });
1772
+ }, { stat: st, summary: "total " + fmt(total2, o) + " across " + v.length + " parts" });
1428
1773
  }
1429
1774
  donut.table = function(o) {
1430
1775
  var v = nums(o.values).map(function(n) {
1431
1776
  return Math.max(0, n);
1432
- }), labels = list(o.labels), total = sum(v);
1777
+ }), labels = list(o.labels), total2 = sum(v);
1433
1778
  return { head: ["Label", "Value", "Share"], rows: v.map(function(n, i) {
1434
- return [labels[i] || "#" + (i + 1), fmt(n, o), (total ? Math.round(n / total * 100) : 0) + "%"];
1779
+ return [labels[i] || "#" + (i + 1), fmt(n, o), (total2 ? Math.round(n / total2 * 100) : 0) + "%"];
1435
1780
  }) };
1436
1781
  };
1437
1782
 
@@ -1500,8 +1845,8 @@ function progress(o, th) {
1500
1845
  var v = nums(o.values).map(function(n) {
1501
1846
  return Math.max(0, n);
1502
1847
  }), labels = list(o.labels), pal = palette(o, th);
1503
- var single = v.length === 1, total = sum(v);
1504
- var max = has(o.max) ? num(o.max, 100) : single ? 100 : total;
1848
+ var single = v.length === 1, total2 = sum(v);
1849
+ var max = has(o.max) ? num(o.max, 100) : single ? 100 : total2;
1505
1850
  if (!(max > 0)) max = 1;
1506
1851
  var auto = !has(o.prefix) && !has(o.suffix) && max === 100 && single;
1507
1852
  var show = function(n) {
@@ -1526,7 +1871,7 @@ function progress(o, th) {
1526
1871
  return tile(o, th, h, function(x0, y0, w, h2) {
1527
1872
  if (!v.length) return emptyState(th, x0, y0, w, h2);
1528
1873
  var s = "", by = y0 + 22, cid = newId("c");
1529
- var head = single ? show(v[0]) + (auto ? "" : " of " + fmt(max, o)) : fmt(total, o) + " of " + fmt(max, o);
1874
+ var head = single ? show(v[0]) + (auto ? "" : " of " + fmt(max, o)) : fmt(total2, o) + " of " + fmt(max, o);
1530
1875
  if (single && labels[0]) s += text(x0, y0 + 11, labels[0], 'fill="' + th.fg + '" font-family="' + SANS + '" font-size="12"');
1531
1876
  s += text(x0 + w, y0 + 11, head, 'text-anchor="end" fill="' + th.fg + '" font-family="' + MONO + '" font-size="11" font-weight="600"');
1532
1877
  s += '<rect x="' + x0 + '" y="' + by + '" width="' + w + '" height="14" rx="7" fill="' + th.grid + '" fill-opacity=".7"/>';
@@ -1554,7 +1899,7 @@ function progress(o, th) {
1554
1899
  s += '<circle cx="' + r2(lx + 4) + '" cy="' + r2(ly) + '" r="4" fill="' + pal[i % pal.length] + '"/><text x="' + r2(lx + 14) + '" y="' + r2(ly + 4) + '" fill="' + th.fg + '" font-family="' + SANS + '" font-size="12">' + esc(it.l) + '<tspan dx="6" fill="' + th.muted + '" font-family="' + MONO + '" font-size="11">' + esc(fmt(v[i], o)) + "</tspan></text>";
1555
1900
  });
1556
1901
  return s;
1557
- }, { stat: st, summary: single ? show(v[0]) + (auto ? "" : " of " + fmt(max, o)) : fmt(total, o) + " of " + fmt(max, o) });
1902
+ }, { stat: st, summary: single ? show(v[0]) + (auto ? "" : " of " + fmt(max, o)) : fmt(total2, o) + " of " + fmt(max, o) });
1558
1903
  }
1559
1904
  progress.table = function(o) {
1560
1905
  var v = nums(o.values).map(function(n) {
@@ -1647,7 +1992,7 @@ register("heatmap", heatmap);
1647
1992
  define("heatmap");
1648
1993
 
1649
1994
  // src/index.js
1650
- var version = "1.4.0";
1995
+ var version = "1.6.0";
1651
1996
  var types = NAMES.slice();
1652
1997
  export {
1653
1998
  BezelChart,