@guiexpert/demo-table-models 1.0.9 → 1.0.11
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/.eslintrc.json +33 -0
- package/dist/README.md +106 -0
- package/dist/demodata/header-groups.d.ts +2 -0
- package/dist/demodata/many-types.d.ts +33 -0
- package/{index.cjs → dist/index.cjs} +280 -15
- package/{index.d.ts → dist/index.d.ts} +5 -1
- package/{index.js → dist/index.js} +2682 -418
- package/dist/lib/createLargeModel.d.ts +13 -0
- package/dist/lib/createManyTypesModel.d.ts +2 -0
- package/{lib → dist/lib}/createOrderModel.d.ts +1 -1
- package/{lib → dist/lib}/createSimplePersonModel.d.ts +1 -1
- package/{lib → dist/lib}/createTimeTableModel.d.ts +10 -9
- package/{lib → dist/lib}/crypto/generateCryptoModel.d.ts +1 -1
- package/{lib → dist/lib}/crypto/renderer/change-percentage-renderer.d.ts +1 -1
- package/{lib → dist/lib}/crypto/renderer/circulating-supply-renderer.d.ts +1 -1
- package/{lib → dist/lib}/crypto/renderer/coin-icon-renderer.d.ts +1 -1
- package/{lib → dist/lib}/crypto/renderer/name-and-symbol-renderer.d.ts +1 -1
- package/{lib → dist/lib}/crypto/renderer/usd-renderer.d.ts +1 -1
- package/{lib → dist/lib}/crypto/renderer/volumn-24h-renderer.d.ts +1 -1
- package/{lib → dist/lib}/generateHeatMapTableModel.d.ts +1 -1
- package/{lib → dist/lib}/generateHeatmapSeattle.d.ts +1 -1
- package/{lib → dist/lib}/generateSimpleModel.d.ts +1 -1
- package/{lib → dist/lib}/generateTreeCheckboxModel.d.ts +1 -1
- package/{lib/generateHeadergroupModel.d.ts → dist/lib/headergroup/generateBigHeadergroupModel.d.ts} +1 -1
- package/dist/lib/headergroup/generateTeamHeadergroupModel.d.ts +9 -0
- package/{lib → dist/lib}/treepeople/generateTreePeopleModel.d.ts +9 -8
- package/dist/model/many-types.if.d.ts +21 -0
- package/dist/package.json +40 -0
- package/package.json +25 -3
- package/patch.js +16 -0
- package/src/demodata/header-groups.ts +152 -0
- package/src/demodata/many-types.ts +1508 -0
- package/src/demodata/orders.ts +1962 -0
- package/src/demodata/persons1000.ts +8006 -0
- package/src/demodata/tree-persons.ts +161880 -0
- package/src/index.ts +26 -0
- package/src/lib/createLargeModel.ts +94 -0
- package/src/lib/createManyTypesModel.ts +210 -0
- package/src/lib/createOrderModel.ts +130 -0
- package/src/lib/createSimplePersonModel.ts +265 -0
- package/src/lib/createTimeTableModel.ts +353 -0
- package/src/lib/crypto/crypto-data.ts +2739 -0
- package/src/lib/crypto/crypto-top.if.ts +19 -0
- package/src/lib/crypto/generateCryptoModel.ts +102 -0
- package/src/lib/crypto/renderer/change-percentage-renderer.ts +30 -0
- package/src/lib/crypto/renderer/circulating-supply-renderer.ts +46 -0
- package/src/lib/crypto/renderer/coin-icon-renderer.ts +25 -0
- package/src/lib/crypto/renderer/name-and-symbol-renderer.ts +31 -0
- package/src/lib/crypto/renderer/usd-renderer.ts +26 -0
- package/src/lib/crypto/renderer/volumn-24h-renderer.ts +35 -0
- package/src/lib/generateHeatMapTableModel.ts +86 -0
- package/src/lib/generateHeatmapSeattle.ts +170 -0
- package/src/lib/generateHeatmapSeattleData.ts +52565 -0
- package/src/lib/generateSimpleModel.ts +31 -0
- package/src/lib/generateTreeCheckboxModel.ts +54 -0
- package/src/lib/headergroup/generateBigHeadergroupModel.ts +62 -0
- package/src/lib/headergroup/generateTeamHeadergroupModel.ts +66 -0
- package/src/lib/treepeople/address.if.ts +7 -0
- package/src/lib/treepeople/address.ts +14 -0
- package/src/lib/treepeople/generateTreePeopleModel.ts +130 -0
- package/src/lib/treepeople/person.if.ts +12 -0
- package/src/lib/treepeople/person.ts +18 -0
- package/src/lib/treepeople/treePeopleData.ts +161878 -0
- package/src/model/address.if.ts +7 -0
- package/src/model/many-types.if.ts +22 -0
- package/src/model/order.if.ts +12 -0
- package/src/model/person.if.ts +12 -0
- package/src/model/simple-person.if.ts +8 -0
- package/tsconfig.json +22 -0
- package/tsconfig.lib.json +10 -0
- package/tsconfig.spec.json +25 -0
- package/vite.config.ts +62 -0
- package/demodata/header-groups.d.ts +0 -2
- /package/{demodata → dist/demodata}/orders.d.ts +0 -0
- /package/{demodata → dist/demodata}/persons1000.d.ts +0 -0
- /package/{demodata → dist/demodata}/tree-persons.d.ts +0 -0
- /package/{lib → dist/lib}/crypto/crypto-data.d.ts +0 -0
- /package/{lib → dist/lib}/crypto/crypto-top.if.d.ts +0 -0
- /package/{lib → dist/lib}/generateHeatmapSeattleData.d.ts +0 -0
- /package/{lib → dist/lib}/treepeople/address.d.ts +0 -0
- /package/{lib → dist/lib}/treepeople/address.if.d.ts +0 -0
- /package/{lib → dist/lib}/treepeople/person.d.ts +0 -0
- /package/{lib → dist/lib}/treepeople/person.if.d.ts +0 -0
- /package/{lib → dist/lib}/treepeople/treePeopleData.d.ts +0 -0
- /package/{model → dist/model}/address.if.d.ts +0 -0
- /package/{model → dist/model}/order.if.d.ts +0 -0
- /package/{model → dist/model}/person.if.d.ts +0 -0
- /package/{model → dist/model}/simple-person.if.d.ts +0 -0
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export interface CryptoTopIf {
|
|
2
|
+
id?: number,
|
|
3
|
+
name: string,
|
|
4
|
+
symbol: string,
|
|
5
|
+
priceInUsd: number,
|
|
6
|
+
change1h: number,
|
|
7
|
+
change24h: number,
|
|
8
|
+
change7d: number,
|
|
9
|
+
change30d: number,
|
|
10
|
+
change60d: number,
|
|
11
|
+
change90d: number,
|
|
12
|
+
marketCapUsd: number,
|
|
13
|
+
volUsd: number,
|
|
14
|
+
volBtc: number,
|
|
15
|
+
circulatingSupply: number,
|
|
16
|
+
maxSupply: number,
|
|
17
|
+
tags: string[],
|
|
18
|
+
|
|
19
|
+
}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ColumnDef,
|
|
3
|
+
ColumnDefIf,
|
|
4
|
+
px100,
|
|
5
|
+
px120,
|
|
6
|
+
px140,
|
|
7
|
+
px160,
|
|
8
|
+
px200,
|
|
9
|
+
px60,
|
|
10
|
+
TableFactory,
|
|
11
|
+
TableModelAndOptions,
|
|
12
|
+
TableModelAndOptionsIf,
|
|
13
|
+
TableOptions,
|
|
14
|
+
TableOptionsIf
|
|
15
|
+
} from "@guiexpert/table";
|
|
16
|
+
import {CryptoTopIf} from "./crypto-top.if";
|
|
17
|
+
import {ChangePercentageRenderer} from "./renderer/change-percentage-renderer";
|
|
18
|
+
import {UsdRenderer} from "./renderer/usd-renderer";
|
|
19
|
+
import {NameAndSymbolRenderer} from "./renderer/name-and-symbol-renderer";
|
|
20
|
+
import {Volumn24hRenderer} from "./renderer/volumn-24h-renderer";
|
|
21
|
+
import {CirculatingSupplyRenderer} from "./renderer/circulating-supply-renderer";
|
|
22
|
+
import {CoinIconRenderer} from "./renderer/coin-icon-renderer";
|
|
23
|
+
import {cryptoData} from "./crypto-data";
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
export function createCryptoModelAndOptions(): TableModelAndOptionsIf {
|
|
27
|
+
|
|
28
|
+
const rows: CryptoTopIf[] = cryptoData;
|
|
29
|
+
const changePercentageRenderer = new ChangePercentageRenderer();
|
|
30
|
+
const usdRenderer = new UsdRenderer();
|
|
31
|
+
const nameAndSymbolRenderer = new NameAndSymbolRenderer();
|
|
32
|
+
const volumn24hRenderer = new Volumn24hRenderer();
|
|
33
|
+
const circulatingSupplyRenderer = new CirculatingSupplyRenderer(120);
|
|
34
|
+
const coinIconRenderer = new CoinIconRenderer();
|
|
35
|
+
|
|
36
|
+
const columnDefs: ColumnDefIf[] = [
|
|
37
|
+
ColumnDef.create({
|
|
38
|
+
property: "symbol",
|
|
39
|
+
headerLabel: "",
|
|
40
|
+
width: px60,
|
|
41
|
+
bodyClasses: ["ge-table-text-align-left"],
|
|
42
|
+
bodyRenderer: coinIconRenderer
|
|
43
|
+
}),
|
|
44
|
+
ColumnDef.create({
|
|
45
|
+
property: "symbol",
|
|
46
|
+
headerLabel: "Name",
|
|
47
|
+
width: px120,
|
|
48
|
+
bodyClasses: ["ge-table-text-align-left"],
|
|
49
|
+
headerClasses: ["ge-table-text-align-left"],
|
|
50
|
+
bodyRenderer: nameAndSymbolRenderer
|
|
51
|
+
}),
|
|
52
|
+
ColumnDef.create({
|
|
53
|
+
property: "priceInUsd",
|
|
54
|
+
headerLabel: "Price $",
|
|
55
|
+
width: px100,
|
|
56
|
+
bodyClasses: ["ge-table-text-align-right"],
|
|
57
|
+
headerClasses: ["ge-table-text-align-right"]
|
|
58
|
+
}),
|
|
59
|
+
new ColumnDef("change1h", "1h %", px100, undefined, ColumnDef.bodyRenderer(changePercentageRenderer)),
|
|
60
|
+
new ColumnDef("change24h", "24h %", px100, undefined, ColumnDef.bodyRenderer(changePercentageRenderer)),
|
|
61
|
+
new ColumnDef("change7d", "7d %", px100, undefined, ColumnDef.bodyRenderer(changePercentageRenderer)),
|
|
62
|
+
ColumnDef.create({
|
|
63
|
+
property: "marketCapUsd",
|
|
64
|
+
headerLabel: "Market Cap",
|
|
65
|
+
width: px160,
|
|
66
|
+
bodyClasses: ["ge-table-text-align-right"],
|
|
67
|
+
headerClasses: ["ge-table-text-align-right"],
|
|
68
|
+
bodyRenderer: usdRenderer
|
|
69
|
+
}),
|
|
70
|
+
ColumnDef.create({
|
|
71
|
+
headerLabel: "Volumne (24h)",
|
|
72
|
+
width: px200,
|
|
73
|
+
bodyClasses: ["ge-table-text-align-right"],
|
|
74
|
+
headerClasses: ["ge-table-text-align-right"],
|
|
75
|
+
bodyRenderer: volumn24hRenderer
|
|
76
|
+
}),
|
|
77
|
+
ColumnDef.create({
|
|
78
|
+
property: "circulatingSupply",
|
|
79
|
+
headerLabel: "Circulating Supply",
|
|
80
|
+
width: px140,
|
|
81
|
+
bodyRenderer: circulatingSupplyRenderer,
|
|
82
|
+
bodyClasses: ["ge-table-text-align-right"],
|
|
83
|
+
headerClasses: ["ge-table-text-align-right"]
|
|
84
|
+
})];
|
|
85
|
+
columnDefs.forEach(cd => cd.sortable = () => true);
|
|
86
|
+
|
|
87
|
+
const tableOptions: TableOptionsIf = {
|
|
88
|
+
...new TableOptions(),
|
|
89
|
+
hoverColumnVisible: false,
|
|
90
|
+
verticalBorderVisible: false,
|
|
91
|
+
defaultRowHeights: {
|
|
92
|
+
header: 34, body: 50, footer: 0
|
|
93
|
+
},
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
return new TableModelAndOptions(
|
|
97
|
+
TableFactory.createTableModel({
|
|
98
|
+
rows, columnDefs, tableOptions
|
|
99
|
+
}),
|
|
100
|
+
tableOptions
|
|
101
|
+
);
|
|
102
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { AreaIdent, AreaModelIf, CellRendererIf, DomServiceIf, RendererCleanupFnType } from "@guiexpert/table";
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
export class ChangePercentageRenderer implements CellRendererIf {
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
render(
|
|
8
|
+
cellDiv: HTMLDivElement,
|
|
9
|
+
_rowIndex: number,
|
|
10
|
+
_columnIndex: number,
|
|
11
|
+
_areaIdent: AreaIdent,
|
|
12
|
+
_areaModel: AreaModelIf,
|
|
13
|
+
cellValue: any,
|
|
14
|
+
domService: DomServiceIf): RendererCleanupFnType | undefined {
|
|
15
|
+
|
|
16
|
+
if (cellValue) {
|
|
17
|
+
const n = Number(cellValue);
|
|
18
|
+
if (n < 0) {
|
|
19
|
+
cellDiv.innerHTML = "▾ " + n.toFixed(2) + "%";
|
|
20
|
+
domService.addClass(cellDiv, "ge-positive-text-color");
|
|
21
|
+
} else {
|
|
22
|
+
cellDiv.innerHTML = "▴ " + n.toFixed(2) + "%";
|
|
23
|
+
domService.addClass(cellDiv, "ge-negative-text-color");
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
return undefined;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
}
|
|
30
|
+
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { AreaIdent, AreaModelIf, CellRendererIf, DomServiceIf, RendererCleanupFnType } from "@guiexpert/table";
|
|
2
|
+
import { CryptoTopIf } from "../crypto-top.if";
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
export class CirculatingSupplyRenderer implements CellRendererIf {
|
|
6
|
+
|
|
7
|
+
private formatter = new Intl.NumberFormat("en-US");
|
|
8
|
+
|
|
9
|
+
constructor(
|
|
10
|
+
private readonly maxWidth: number = 120) {
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
render(
|
|
14
|
+
cellDiv: HTMLDivElement,
|
|
15
|
+
rowIndex: number,
|
|
16
|
+
_columnIndex: number,
|
|
17
|
+
_areaIdent: AreaIdent,
|
|
18
|
+
areaModel: AreaModelIf,
|
|
19
|
+
_cellValue: any,
|
|
20
|
+
_domService: DomServiceIf): RendererCleanupFnType | undefined {
|
|
21
|
+
|
|
22
|
+
const coin: CryptoTopIf = areaModel.getRowByIndex(rowIndex);
|
|
23
|
+
if (coin) {
|
|
24
|
+
const cs = this.formatter.format(coin.circulatingSupply);
|
|
25
|
+
const max = coin.maxSupply;
|
|
26
|
+
const buf: string[] = [];
|
|
27
|
+
buf.push("<div style=\"line-height: 1.2;padding: 10px 0 0 10px;\">");
|
|
28
|
+
buf.push(cs);
|
|
29
|
+
buf.push("<br>");
|
|
30
|
+
if (max) {
|
|
31
|
+
const w = this.maxWidth * coin.circulatingSupply / max;
|
|
32
|
+
buf.push(`
|
|
33
|
+
<div style="width: ${this.maxWidth}px;height: 5px;background-color: #eee;margin:10px 0 0 10px">
|
|
34
|
+
<div style="width: ${w}px;height: 5px;background-color: #ccc;"></div>
|
|
35
|
+
</div>
|
|
36
|
+
`);
|
|
37
|
+
}
|
|
38
|
+
buf.push("</div>");
|
|
39
|
+
|
|
40
|
+
cellDiv.innerHTML = buf.join("");
|
|
41
|
+
}
|
|
42
|
+
return undefined;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
}
|
|
46
|
+
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { AreaIdent, AreaModelIf, CellRendererIf, DomServiceIf, RendererCleanupFnType } from "@guiexpert/table";
|
|
2
|
+
import { CryptoTopIf } from "../crypto-top.if";
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
export class CoinIconRenderer implements CellRendererIf {
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
render(
|
|
9
|
+
cellDiv: HTMLDivElement,
|
|
10
|
+
rowIndex: number,
|
|
11
|
+
_columnIndex: number,
|
|
12
|
+
_areaIdent: AreaIdent,
|
|
13
|
+
areaModel: AreaModelIf,
|
|
14
|
+
_cellValue: any,
|
|
15
|
+
_domService: DomServiceIf): RendererCleanupFnType | undefined {
|
|
16
|
+
|
|
17
|
+
const coin: CryptoTopIf = areaModel.getRowByIndex(rowIndex);
|
|
18
|
+
if (coin?.id) {
|
|
19
|
+
cellDiv.innerHTML = `<img src="https://s2.coinmarketcap.com/static/img/coins/64x64/${coin.id}.png" style="width:30px;height: 30px;margin: 10px 10px 0 20px;">`;
|
|
20
|
+
}
|
|
21
|
+
return undefined;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
}
|
|
25
|
+
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { AreaIdent, AreaModelIf, CellRendererIf, DomServiceIf, RendererCleanupFnType } from "@guiexpert/table";
|
|
2
|
+
import { CryptoTopIf } from "../crypto-top.if";
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
export class NameAndSymbolRenderer implements CellRendererIf {
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
render(
|
|
9
|
+
cellDiv: HTMLDivElement,
|
|
10
|
+
rowIndex: number,
|
|
11
|
+
_columnIndex: number,
|
|
12
|
+
_areaIdent: AreaIdent,
|
|
13
|
+
areaModel: AreaModelIf,
|
|
14
|
+
_cellValue: any,
|
|
15
|
+
_domService: DomServiceIf): RendererCleanupFnType | undefined {
|
|
16
|
+
|
|
17
|
+
const coin: CryptoTopIf = areaModel.getRowByIndex(rowIndex);
|
|
18
|
+
if (coin) {
|
|
19
|
+
const name = coin.name ?? coin.symbol;
|
|
20
|
+
cellDiv.innerHTML = `
|
|
21
|
+
<div style="line-height: 1.2;padding: 10px 0 0 10px;">
|
|
22
|
+
${name}<br>
|
|
23
|
+
${coin.symbol}
|
|
24
|
+
</div>
|
|
25
|
+
`;
|
|
26
|
+
}
|
|
27
|
+
return undefined;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
}
|
|
31
|
+
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { AreaIdent, AreaModelIf, CellRendererIf, DomServiceIf, RendererCleanupFnType } from "@guiexpert/table";
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
export class UsdRenderer implements CellRendererIf {
|
|
5
|
+
|
|
6
|
+
private formatter = new Intl.NumberFormat("en-US", { style: "currency", currency: "USD" });
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
render(
|
|
10
|
+
cellDiv: HTMLDivElement,
|
|
11
|
+
_rowIndex: number,
|
|
12
|
+
_columnIndex: number,
|
|
13
|
+
_areaIdent: AreaIdent,
|
|
14
|
+
_areaModel: AreaModelIf,
|
|
15
|
+
cellValue: any,
|
|
16
|
+
_domService: DomServiceIf): RendererCleanupFnType | undefined {
|
|
17
|
+
|
|
18
|
+
if (cellValue) {
|
|
19
|
+
const n = Number(cellValue);
|
|
20
|
+
cellDiv.innerText = this.formatter.format(n);
|
|
21
|
+
}
|
|
22
|
+
return undefined;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
}
|
|
26
|
+
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { AreaIdent, AreaModelIf, CellRendererIf, DomServiceIf, RendererCleanupFnType } from "@guiexpert/table";
|
|
2
|
+
import { CryptoTopIf } from "../crypto-top.if";
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
export class Volumn24hRenderer implements CellRendererIf {
|
|
6
|
+
|
|
7
|
+
private formatterUsd = new Intl.NumberFormat("en-US", { style: "currency", currency: "USD" });
|
|
8
|
+
private formatter = new Intl.NumberFormat("en-US");
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
render(
|
|
12
|
+
cellDiv: HTMLDivElement,
|
|
13
|
+
rowIndex: number,
|
|
14
|
+
_columnIndex: number,
|
|
15
|
+
_areaIdent: AreaIdent,
|
|
16
|
+
areaModel: AreaModelIf,
|
|
17
|
+
_cellValue: any,
|
|
18
|
+
_domService: DomServiceIf): RendererCleanupFnType | undefined {
|
|
19
|
+
|
|
20
|
+
const coin: CryptoTopIf = areaModel.getRowByIndex(rowIndex);
|
|
21
|
+
if (coin) {
|
|
22
|
+
const usd = this.formatterUsd.format(coin.volUsd);
|
|
23
|
+
const btc = this.formatter.format(coin.volBtc);
|
|
24
|
+
cellDiv.innerHTML = `
|
|
25
|
+
<div style="line-height: 1.2;padding: 10px 0 0 10px;">
|
|
26
|
+
${usd}<br>
|
|
27
|
+
${btc} BTC
|
|
28
|
+
</div>
|
|
29
|
+
`;
|
|
30
|
+
}
|
|
31
|
+
return undefined;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
}
|
|
35
|
+
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { AreaModelArrayOfArrays, DefaultRowHeights, TableFactory, TableModelIf } from "@guiexpert/table";
|
|
2
|
+
|
|
3
|
+
const defaultRowHeights = new DefaultRowHeights(34, 50, 0);
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
const headerLabel = "_ Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec".split(" ");
|
|
7
|
+
|
|
8
|
+
const data: number[][] =
|
|
9
|
+
`2009 27.9 36.7 42.4 54.5 62.5 67.5 72.7 75.7 66.3 55.0 51.2 35.9
|
|
10
|
+
2010 32.5 33.1 48.2 57.9 65.3 74.7 81.3 77.4 71.1 58.1 47.9 32.8
|
|
11
|
+
2011 29.7 36.0 42.3 54.3 64.5 72.3 80.2 75.3 70.0 57.1 51.9 43.3
|
|
12
|
+
2012 37.3 40.9 50.9 54.8 65.1 71.0 78.8 76.7 68.8 58.0 43.9 41.5
|
|
13
|
+
2013 35.1 33.9 40.1 53.0 62.8 72.7 79.8 74.6 67.9 60.2 45.3 38.5
|
|
14
|
+
2014 28.6 31.6 37.7 52.3 64.0 72.5 76.1 74.5 69.7 59.6 45.3 40.5
|
|
15
|
+
2015 29.9 23.9 38.1 54.3 68.5 71.2 78.8 79.0 74.5 58.0 52.8 50.8
|
|
16
|
+
2016 34.5 37.7 48.9 53.3 62.8 72.3 78.7 79.2 71.8 58.8 49.8 38.3
|
|
17
|
+
2017 38.0 41.6 39.2 57.2 61.1 72.0 76.8 74.0 70.5 64.1 46.6 33.4`
|
|
18
|
+
.split("\n")
|
|
19
|
+
.map(row => row
|
|
20
|
+
.split(" ")
|
|
21
|
+
.map(s => Number(s))
|
|
22
|
+
);
|
|
23
|
+
|
|
24
|
+
const MIN = 27.9;
|
|
25
|
+
const MAX = 77.4;
|
|
26
|
+
|
|
27
|
+
// function getHsl(v: number): string {
|
|
28
|
+
// const normalizedValue0to1 = (v - MIN) / (MAX - MIN);
|
|
29
|
+
// const h = Math.floor((1 - normalizedValue0to1) * 360);
|
|
30
|
+
// return `hsl(${h}deg ,100% ,50%)`;
|
|
31
|
+
// }
|
|
32
|
+
|
|
33
|
+
class RGB {
|
|
34
|
+
constructor(
|
|
35
|
+
public r: number,
|
|
36
|
+
public g: number,
|
|
37
|
+
public b: number
|
|
38
|
+
) {
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function normalize(value: number, fromSource: number, toSource: number, fromTarget: number, toTarget: number) {
|
|
43
|
+
return (value - fromSource) / (toSource - fromSource) * (toTarget - fromTarget) + fromTarget;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function getTwoColorGradientRGB(min: number, max: number, value: number): string {
|
|
47
|
+
var startRGB = new RGB(255, 0, 0);
|
|
48
|
+
var endRGB = new RGB(0, 0, 255);
|
|
49
|
+
var percentFade = normalize(value, min, max, 0, 1);
|
|
50
|
+
|
|
51
|
+
var diffRed = endRGB.r - startRGB.r;
|
|
52
|
+
var diffGreen = endRGB.g - startRGB.g;
|
|
53
|
+
var diffBlue = endRGB.b - startRGB.b;
|
|
54
|
+
|
|
55
|
+
diffRed = (diffRed * percentFade) + startRGB.r;
|
|
56
|
+
diffGreen = (diffGreen * percentFade) + startRGB.g;
|
|
57
|
+
diffBlue = (diffBlue * percentFade) + startRGB.b;
|
|
58
|
+
|
|
59
|
+
return `rgb(${Math.round(diffRed)}, ${Math.round(diffGreen)}, ${Math.round(diffBlue)})`;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
export function createHeatMapModel(): TableModelIf {
|
|
64
|
+
const bodyAreaModel = new AreaModelArrayOfArrays("body", data, defaultRowHeights.body);
|
|
65
|
+
const columnSizes = new Array(headerLabel.length).fill(50);
|
|
66
|
+
const headerAreaModel = new AreaModelArrayOfArrays("header", [headerLabel], defaultRowHeights.header);
|
|
67
|
+
|
|
68
|
+
bodyAreaModel.getCustomStyleAt = (rowIndex: number, columnIndex: number) => {
|
|
69
|
+
let ret: { [key: string]: string } = {};
|
|
70
|
+
if (columnIndex > 0) {
|
|
71
|
+
const n = bodyAreaModel.getValueAt(rowIndex, columnIndex) as number;
|
|
72
|
+
ret = {
|
|
73
|
+
"background": getTwoColorGradientRGB(MIN, MAX, n),
|
|
74
|
+
"color": "#fff"
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
ret["paddingTop"] = "10px";
|
|
78
|
+
return ret;
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
return TableFactory.createTableModel({
|
|
82
|
+
headerAreaModel,
|
|
83
|
+
bodyAreaModel,
|
|
84
|
+
columnSizes
|
|
85
|
+
});
|
|
86
|
+
}
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
import { getRawData, RawData } from "./generateHeatmapSeattleData";
|
|
2
|
+
import {
|
|
3
|
+
AreaModel,
|
|
4
|
+
ColorRgb,
|
|
5
|
+
GeCssColorUtil,
|
|
6
|
+
TableFactory,
|
|
7
|
+
TableModelIf,
|
|
8
|
+
ThreeColorGradientArg
|
|
9
|
+
} from "@guiexpert/table";
|
|
10
|
+
|
|
11
|
+
const defaultRowHeights = 30;
|
|
12
|
+
const defaultColumnWidth = 3;
|
|
13
|
+
const data: RawData[] = getRawData();
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
const map: { [key: string]: { [key: string]: RawData } } = {};
|
|
17
|
+
data.forEach(item => {
|
|
18
|
+
const [d, t] = item.date.split("T") as [string, string];
|
|
19
|
+
if (!map[d]) {
|
|
20
|
+
map[d] = {};
|
|
21
|
+
}
|
|
22
|
+
map[d][t.substring(0, 5)] = item;
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
const days = Object.keys(map);
|
|
27
|
+
const times = ["06:00", "07:00", "08:00", "09:00", "10:00", "11:00", "12:00", "13:00",
|
|
28
|
+
"14:00", "15:00", "16:00", "17:00", "18:00", "19:00", "20:00", "21:00", "22:00", "23:00",
|
|
29
|
+
"00:00", "01:00", "02:00", "03:00", "04:00", "05:00"];
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
function getMinMax(): [number, number] {
|
|
33
|
+
let min = 10;
|
|
34
|
+
let max = 0;
|
|
35
|
+
data.forEach(item => {
|
|
36
|
+
min = Math.min(min, item.temperature);
|
|
37
|
+
max = Math.max(max, item.temperature);
|
|
38
|
+
});
|
|
39
|
+
return [min, max];
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const [MIN, MAX] = getMinMax();
|
|
43
|
+
|
|
44
|
+
export function createHeatMapSeattleModel(): TableModelIf {
|
|
45
|
+
const bodyAreaModel = new HeatMapSeattleBodyModel();
|
|
46
|
+
const footerAreaModel = new HeatMapSeattleFooterModel();
|
|
47
|
+
const columnSizes = [60, ...(new Array(days.length).fill(defaultColumnWidth))];
|
|
48
|
+
|
|
49
|
+
return TableFactory.createTableModel({
|
|
50
|
+
bodyAreaModel,
|
|
51
|
+
footerAreaModel,
|
|
52
|
+
columnSizes,
|
|
53
|
+
fixedLeftColumnCount: 1
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// TODO split time vs date, see https://vega.github.io/vega/examples/heatmap/
|
|
58
|
+
// colors from #430355 -> #1F908D -> #FAE625
|
|
59
|
+
|
|
60
|
+
class HeatMapSeattleBodyModel extends AreaModel {
|
|
61
|
+
|
|
62
|
+
override getRowCount(): number {
|
|
63
|
+
return times.length;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
override getRowHeight(_rowIndex: number): number {
|
|
67
|
+
return defaultRowHeights;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
override getValueAt(rowIndex: number, columnIndex: number): any {
|
|
71
|
+
if (columnIndex === 0) return times[rowIndex];
|
|
72
|
+
return "";
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
override getTooltipAt(rowIndex: number, columnIndex: number): any {
|
|
77
|
+
if (columnIndex === 0) {
|
|
78
|
+
return "";
|
|
79
|
+
}
|
|
80
|
+
columnIndex--;
|
|
81
|
+
const date = days[columnIndex];
|
|
82
|
+
const time = times[rowIndex];
|
|
83
|
+
if (map[date] && map[date][time]) {
|
|
84
|
+
return `${date} ${time} → ${map[date][time].temperature}`;
|
|
85
|
+
}
|
|
86
|
+
return "";
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
override getCustomStyleAt(rowIndex: number, columnIndex: number): { [p: string]: string } | undefined {
|
|
90
|
+
if (columnIndex === 0) {
|
|
91
|
+
return undefined;
|
|
92
|
+
}
|
|
93
|
+
columnIndex--;
|
|
94
|
+
const date = days[columnIndex];
|
|
95
|
+
const time = times[rowIndex];
|
|
96
|
+
if (!map[date] || !map[date][time]) return undefined;
|
|
97
|
+
|
|
98
|
+
const n = map[date][time].temperature;
|
|
99
|
+
|
|
100
|
+
// const red = new ColorRgb(255, 0, 0);
|
|
101
|
+
// const blue = new ColorRgb(0, 0, 255);
|
|
102
|
+
// const p = new TwoColorGradientArg(MIN, red, MAX, blue);
|
|
103
|
+
// -> "background": GeCssColorUtil.getTwoColorGradientRGB(n, p),
|
|
104
|
+
|
|
105
|
+
const minColor = new ColorRgb(67, 1, 84);
|
|
106
|
+
const middleColor = new ColorRgb(31, 144, 141);
|
|
107
|
+
const maxColor = new ColorRgb(250, 230, 37);
|
|
108
|
+
const MIDDLE = (MAX + MIN) / 2;
|
|
109
|
+
const p = new ThreeColorGradientArg(MIN, minColor, MIDDLE, middleColor, MAX, maxColor);
|
|
110
|
+
|
|
111
|
+
return {
|
|
112
|
+
"background": GeCssColorUtil.getThreeColorGradientRGB(n, p),
|
|
113
|
+
"color": "transparent" // we only want to show the bg color
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
class HeatMapSeattleFooterModel extends AreaModel {
|
|
120
|
+
|
|
121
|
+
override getRowCount(): number {
|
|
122
|
+
return 1;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
override getRowHeight(_rowIndex: number): number {
|
|
126
|
+
return defaultRowHeights;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
override getValueAt(_rowIndex: number, columnIndex: number): any {
|
|
130
|
+
if (columnIndex === 1) return "Jan";
|
|
131
|
+
if (columnIndex === 32) return "Feb";
|
|
132
|
+
if (columnIndex === 60) return "Mar";
|
|
133
|
+
if (columnIndex === 91) return "Apr";
|
|
134
|
+
if (columnIndex === 121) return "May";
|
|
135
|
+
if (columnIndex === 152) return "Jun";
|
|
136
|
+
if (columnIndex === 182) return "Jul";
|
|
137
|
+
if (columnIndex === 213) return "Aug";
|
|
138
|
+
if (columnIndex === 244) return "Sep";
|
|
139
|
+
if (columnIndex === 274) return "Oct";
|
|
140
|
+
if (columnIndex === 305) return "Nov";
|
|
141
|
+
if (columnIndex === 335) return "Dec";
|
|
142
|
+
return "";
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
override getColspanAt(_rowIndex: number, columnIndex: number): number {
|
|
146
|
+
if (columnIndex === 1) return 31;
|
|
147
|
+
if (columnIndex === 32) return 28;
|
|
148
|
+
if (columnIndex === 60) return 31;
|
|
149
|
+
if (columnIndex === 91) return 30;
|
|
150
|
+
if (columnIndex === 121) return 31;
|
|
151
|
+
if (columnIndex === 152) return 30;
|
|
152
|
+
if (columnIndex === 182) return 31;
|
|
153
|
+
if (columnIndex === 213) return 31;
|
|
154
|
+
if (columnIndex === 244) return 30;
|
|
155
|
+
if (columnIndex === 274) return 31;
|
|
156
|
+
if (columnIndex === 305) return 30;
|
|
157
|
+
if (columnIndex === 335) return 31;
|
|
158
|
+
return 0;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
override getMaxColspan(): number {
|
|
162
|
+
return 32;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
override getCustomStyleAt(_rowIndex: number, columnIndex: number): { [p: string]: string } | undefined {
|
|
166
|
+
return {
|
|
167
|
+
"border-left": columnIndex > 2 ? "solid 1px #555" : "none"
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
}
|