mapcomplete/UI/BigComponents/Histogram.ts

74 lines
No EOL
2.5 KiB
TypeScript

import {VariableUiElement} from "../Base/VariableUIElement";
import {UIEventSource} from "../../Logic/UIEventSource";
import Table from "../Base/Table";
import Combine from "../Base/Combine";
import {FixedUiElement} from "../Base/FixedUiElement";
import {Utils} from "../../Utils";
import BaseUIElement from "../BaseUIElement";
import Translations from "../i18n/Translations";
export default class Histogram<T> extends VariableUiElement {
private static defaultPalette = [
"#ff5858",
"#ffad48",
"#ffff59",
"#9d62d9",
"#56bd56",
"#63a9ff",
"#fa61fa"
]
constructor(values: UIEventSource<string[]>,
title: string | BaseUIElement,
countTitle: string | BaseUIElement,
assignColor?: (t0: string) => string
) {
super(values.map(values => {
if (values === undefined) {
return undefined;
}
values = Utils.NoNull(values)
const counts = new Map<string, number>()
for (const value of values) {
const c = counts.get(value) ?? 0;
counts.set(value, c + 1);
}
const keys = Array.from(counts.keys());
keys.sort()
const max = Math.max(...Array.from(counts.values()))
const fallbackColor = (keyValue: string) => {
const index = keys.indexOf(keyValue)
return Histogram.defaultPalette[index % Histogram.defaultPalette.length]
};
let actualAssignColor = undefined;
if (assignColor === undefined) {
actualAssignColor = fallbackColor;
} else {
actualAssignColor = (keyValue: string) => {
return assignColor(keyValue) ?? fallbackColor(keyValue)
}
}
return new Table(
[Translations.W(title), countTitle],
keys.map(key => [
key,
new Combine([
new Combine([new FixedUiElement("" + counts.get(key)).SetClass("font-bold rounded-full block")])
.SetClass("flex justify-center rounded border border-black")
.SetStyle(`background: ${actualAssignColor(key)}; width: ${100 * counts.get(key) / max}%`)
]).SetClass("block w-full")
]),
keys.map(_ => ["width: 20%"])
).SetClass("w-full");
}));
}
}