aboutsummaryrefslogtreecommitdiffstats
path: root/webstats/plots.js
diff options
context:
space:
mode:
authorOscar Najera <hi@oscarnajera.com>2025-04-27 22:33:44 +0200
committerOscar Najera <hi@oscarnajera.com>2025-04-27 22:33:44 +0200
commitb46f51a0b3e2e1eb4262c393ac9468802de86c67 (patch)
treee380b9eff0971b37ebf320b7c7ced9eb35388974 /webstats/plots.js
parentbb83ef6079eef26fb82f8578564238297b7c0b91 (diff)
downloadscratch-b46f51a0b3e2e1eb4262c393ac9468802de86c67.tar.gz
scratch-b46f51a0b3e2e1eb4262c393ac9468802de86c67.tar.bz2
scratch-b46f51a0b3e2e1eb4262c393ac9468802de86c67.zip
work for robots text
Diffstat (limited to 'webstats/plots.js')
-rw-r--r--webstats/plots.js317
1 files changed, 317 insertions, 0 deletions
diff --git a/webstats/plots.js b/webstats/plots.js
new file mode 100644
index 0000000..d861450
--- /dev/null
+++ b/webstats/plots.js
@@ -0,0 +1,317 @@
+function isObject(value) {
+ return (
+ value !== null &&
+ typeof value === "object" &&
+ !Array.isArray(value) &&
+ !(value instanceof Element)
+ );
+}
+function attrTrans(key) {
+ switch (key) {
+ case "class":
+ return "className";
+ case "for":
+ return "htmlFor";
+ default:
+ return key;
+ }
+}
+var tagRe = /([^\s.#]+)(?:#([^\s.#]+))?(?:.([^\s#]+))?/;
+function domTag(infoTag) {
+ var _db1 = infoTag.match(tagRe);
+ var _ = _db1[0];
+ var tag = _db1[1];
+ var id = _db1[2];
+ var className = _db1[3];
+ var el = document.createElement(tag);
+ if (id) {
+ el.id = id;
+ }
+ if (className) {
+ el.className = className.replaceAll(".", " ");
+ }
+ __PS_MV_REG = [];
+ return el;
+}
+function fillAttrs(el, attrs) {
+ if (isObject(attrs)) {
+ for (var key in attrs) {
+ if (key.startsWith("data-")) {
+ el.setAttribute(key, attrs[key]);
+ } else if (key === "style") {
+ Object.assign(el[key], attrs[key]);
+ } else {
+ el[attrTrans(key)] = attrs[key];
+ }
+ }
+ __PS_MV_REG = [];
+ return true;
+ }
+}
+function domEl() {
+ var params = Array.prototype.slice.call(arguments, 0);
+ if (Array.isArray(params[0])) {
+ __PS_MV_REG = [];
+ return domEl.apply(this, params[0]);
+ } else {
+ var el = domTag(params[0]);
+ var contents = params.slice(fillAttrs(el, params[1]) ? 2 : 1);
+ for (const arg of contents) {
+ if (Array.isArray(arg)) {
+ el.appendChild(domEl(arg));
+ } else if (arg instanceof Element) {
+ el.appendChild(arg);
+ } else if (arg && typeof arg === "string") {
+ el.appendChild(document.createTextNode(arg));
+ }
+ }
+ __PS_MV_REG = [];
+ return el;
+ }
+}
+function logger(level, obj) {
+ var objects = Array.prototype.slice.call(arguments, 2);
+ console[level].apply(console, [obj].concat(objects));
+ __PS_MV_REG = [];
+ return obj;
+}
+function responseToJson(response) {
+ if (response.ok) {
+ __PS_MV_REG = [];
+ return response.json().then(function (value) {
+ if (value["error"]) {
+ throw new Error(value["error"]);
+ } else {
+ __PS_MV_REG = [];
+ return value;
+ }
+ });
+ } else {
+ throw new Error("not 2XX resp");
+ }
+}
+function csvFloat(data) {
+ let headers = data[0];
+ let series = headers.map((_, idx) =>
+ data.slice(1).map((row) => parseFloat(row[idx])),
+ );
+ return [headers, series];
+}
+function responseParseCSV(response) {
+ if (response.ok)
+ return response.text().then((data) =>
+ data
+ .split(/\n/)
+ .filter((x) => x)
+ .map((row) => row.split(/,/)),
+ );
+ throw new Error("not 2XX resp");
+}
+
+function withSuffix(val, suffix) {
+ return val.toFixed(1).replace(/.?0+$/, "").concat("", suffix);
+}
+function siScaling(value) {
+ var v = Math.abs(value);
+ return 0 === v
+ ? [0, ""]
+ : v >= 1000000000000000.0
+ ? [value / 1000000000000000.0, "P"]
+ : v >= 1000000000000.0
+ ? [value / 1000000000000.0, "T"]
+ : v >= 1000000000.0
+ ? [value / 1000000000.0, "G"]
+ : v >= 1000000.0
+ ? [value / 1000000.0, "M"]
+ : v >= 1000.0
+ ? [value / 1000.0, "K"]
+ : v >= 0.6
+ ? [value, ""]
+ : v >= 0.001
+ ? [value / 0.001, "m"]
+ : v >= 0.000001
+ ? [value / 0.000001, "μ"]
+ : v >= 0.000000001
+ ? [value / 0.000000001, "n"]
+ : v >= 0.000000000001
+ ? [value / 0.000000000001, "p"]
+ : null;
+}
+function scaling(val) {
+ return withSuffix.apply(this, siScaling(val));
+}
+
+function spacedColor(idx, alpha) {
+ if (alpha === undefined) {
+ alpha = "/ 1";
+ }
+ return "hsl(" + 137.506 * idx + " 70% 55% " + alpha + ")";
+}
+
+function makeChart(data, container) {
+ const opts = {
+ title: "Server Events",
+ width: 920,
+ height: 600,
+ // ms: 1,
+ // cursor: {
+ // x: false,
+ // y: false,
+ // },
+ series: [
+ {},
+ {
+ label: "hits",
+ stroke: "red",
+ // scale: "%",
+ value: (u, v) => scaling(v),
+ // width: 1 / devicePixelRatio,
+ },
+ // {
+ // label: "visits",
+ // stroke: "blue",
+ // // scale: "%",
+ // // value: (u, v) => (v == null ? null : v.toFixed(1) + "%"),
+ // // width: 1 / devicePixelRatio,
+ // },
+ {
+ label: "tx",
+ scale: "mb",
+ stroke: "green",
+ value: (u, v) => (v == null ? null : scaling(v) + "B"),
+ width: 1 / devicePixelRatio,
+ },
+ ],
+ axes: [
+ {},
+ {
+ values: (u, vals, space) => vals.map(scaling),
+ },
+ {
+ side: 1,
+ scale: "mb",
+ size: 60,
+ values: (u, vals, space) => vals.map((v) => scaling(v) + "B"),
+ grid: { show: false },
+ stroke: "green",
+ },
+ ],
+ };
+
+ let uplot = new uPlot(opts, data, container);
+ container["uobj"] = uplot;
+}
+
+function agentChart(header, series, container) {
+ const opts = {
+ width: 920,
+ height: 600,
+ hooks: {
+ setSeries: [
+ (u, seriesIdx, opts) => {
+ if (opts.focus != null) {
+ u.series.forEach((s, i) => {
+ s.width = i == seriesIdx ? 3 : 1;
+ });
+ }
+ },
+ ],
+ },
+ focus: { alpha: 0.5 },
+ cursor: {
+ focus: {
+ prox: 1e6,
+ bias: 0,
+ dist: (self, seriesIdx, dataIdx, valPos, curPos) => {
+ return valPos - curPos;
+ },
+ },
+ },
+
+ series: [
+ {},
+ {
+ label: header[1],
+ stroke: "black",
+ dash: [10, 5],
+ value: (u, v) => scaling(v),
+ scale: "hits",
+ },
+ ].concat(
+ header.slice(2).map((name, idx) => ({
+ label: name,
+ stroke: spacedColor(idx),
+ fill: spacedColor(idx, "/ 0.1"),
+ value: (u, v) => scaling(v) + "B",
+ })),
+ ),
+ axes: [
+ {},
+ {
+ values: (u, vals, space) => vals.map((v) => (v ? scaling(v) + "B" : v)),
+ size: 60,
+ label: "Bandwidth",
+ labelSize: 50,
+ },
+ {
+ side: 1,
+ scale: "hits",
+ label: "Requests",
+ grid: { show: false },
+ values: (u, vals, space) => vals.map((v) => (v ? scaling(v) : v)),
+ labelSize: 50,
+ },
+ ],
+ };
+ let uplot = new uPlot(opts, series, container);
+ container["uobj"] = uplot;
+}
+addEventListener("load", () => {
+ fetch("/top_agent_traffic.csv")
+ .then(responseParseCSV)
+ .then(csvFloat)
+ .then(([headers, series]) => {
+ let cont = document.querySelector("#agent-traffic").parentNode;
+ cont.innerHTML = "";
+ agentChart(headers, series, cont);
+ });
+
+ fetch("/fails.csv")
+ .then(responseParseCSV)
+ .then((data) => {
+ let headers = data[0];
+ return data
+ .slice(1)
+ .map((row) => [
+ "tr",
+ ["td.org-right", scaling(parseFloat(row[0]))],
+ ["td.org-right", scaling(parseFloat(row[1])) + "B"],
+ ["td.org-left", decodeURI(row[2])],
+ ]);
+ })
+ .then((series) => {
+ let table = [
+ "table",
+ {
+ border: 2,
+ cellPadding: 6,
+ cellSpacing: 0,
+ rules: "groups",
+ frame: "hsides",
+ },
+ [
+ "thead",
+ [
+ "tr",
+ ["th.org-right", "hits"],
+ ["th.org-right", "tx"],
+ ["th.org-left", "path"],
+ ],
+ ],
+ ];
+ let tbody = ["tbody"].concat(series);
+ table.push(tbody);
+ console.log(table);
+ document.body.appendChild(domEl(table));
+ });
+});