forked from MapComplete/MapComplete
Refactoring: move all code files into a src directory
This commit is contained in:
parent
de99f56ca8
commit
e75d2789d2
389 changed files with 0 additions and 12 deletions
154
src/UI/BigComponents/Histogram.ts
Normal file
154
src/UI/BigComponents/Histogram.ts
Normal file
|
|
@ -0,0 +1,154 @@
|
|||
import { VariableUiElement } from "../Base/VariableUIElement"
|
||||
import { Store, 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 Svg from "../../Svg"
|
||||
|
||||
export default class Histogram<T> extends VariableUiElement {
|
||||
private static defaultPalette = [
|
||||
"#ff5858",
|
||||
"#ffad48",
|
||||
"#ffff59",
|
||||
"#56bd56",
|
||||
"#63a9ff",
|
||||
"#9d62d9",
|
||||
"#fa61fa",
|
||||
]
|
||||
|
||||
constructor(
|
||||
values: Store<string[]>,
|
||||
title: string | BaseUIElement,
|
||||
countTitle: string | BaseUIElement,
|
||||
options?: {
|
||||
assignColor?: (t0: string) => string
|
||||
sortMode?: "name" | "name-rev" | "count" | "count-rev"
|
||||
}
|
||||
) {
|
||||
const sortMode = new UIEventSource<"name" | "name-rev" | "count" | "count-rev">(
|
||||
options?.sortMode ?? "name"
|
||||
)
|
||||
const sortName = new VariableUiElement(
|
||||
sortMode.map((m) => {
|
||||
switch (m) {
|
||||
case "name":
|
||||
return Svg.up_svg()
|
||||
case "name-rev":
|
||||
return Svg.up_svg().SetStyle("transform: rotate(180deg)")
|
||||
default:
|
||||
return Svg.circle_svg()
|
||||
}
|
||||
})
|
||||
)
|
||||
const titleHeader = new Combine([sortName.SetClass("w-4 mr-2"), title])
|
||||
.SetClass("flex")
|
||||
.onClick(() => {
|
||||
if (sortMode.data === "name") {
|
||||
sortMode.setData("name-rev")
|
||||
} else {
|
||||
sortMode.setData("name")
|
||||
}
|
||||
})
|
||||
|
||||
const sortCount = new VariableUiElement(
|
||||
sortMode.map((m) => {
|
||||
switch (m) {
|
||||
case "count":
|
||||
return Svg.up_svg()
|
||||
case "count-rev":
|
||||
return Svg.up_svg().SetStyle("transform: rotate(180deg)")
|
||||
default:
|
||||
return Svg.circle_svg()
|
||||
}
|
||||
})
|
||||
)
|
||||
|
||||
const countHeader = new Combine([sortCount.SetClass("w-4 mr-2"), countTitle])
|
||||
.SetClass("flex")
|
||||
.onClick(() => {
|
||||
if (sortMode.data === "count-rev") {
|
||||
sortMode.setData("count")
|
||||
} else {
|
||||
sortMode.setData("count-rev")
|
||||
}
|
||||
})
|
||||
|
||||
const header = [titleHeader, countHeader]
|
||||
|
||||
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())
|
||||
|
||||
switch (sortMode.data) {
|
||||
case "name":
|
||||
keys.sort()
|
||||
break
|
||||
case "name-rev":
|
||||
keys.sort().reverse(/*Copy of array, inplace reverse if fine*/)
|
||||
break
|
||||
case "count":
|
||||
keys.sort((k0, k1) => counts.get(k0) - counts.get(k1))
|
||||
break
|
||||
case "count-rev":
|
||||
keys.sort((k0, k1) => counts.get(k1) - counts.get(k0))
|
||||
break
|
||||
}
|
||||
|
||||
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 (options?.assignColor === undefined) {
|
||||
actualAssignColor = fallbackColor
|
||||
} else {
|
||||
actualAssignColor = (keyValue: string) => {
|
||||
return options.assignColor(keyValue) ?? fallbackColor(keyValue)
|
||||
}
|
||||
}
|
||||
|
||||
return new Table(
|
||||
header,
|
||||
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"),
|
||||
]),
|
||||
{
|
||||
contentStyle: keys.map((_) => ["width: 20%"]),
|
||||
}
|
||||
).SetClass("w-full zebra-table")
|
||||
},
|
||||
[sortMode]
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue