Start working on the Stats Viewer application

This commit is contained in:
Oliver-Akins 2025-04-21 00:50:58 -06:00
parent cb3bc7c86c
commit 91863d85a8
18 changed files with 422 additions and 1 deletions

128
module/Apps/StatsViewer.mjs Normal file
View file

@ -0,0 +1,128 @@
import { filePath } from "../consts.mjs";
import { Logger } from "../utils/Logger.mjs";
const { HandlebarsApplicationMixin, ApplicationV2 } = foundry.applications.api;
export class StatsViewer extends HandlebarsApplicationMixin(ApplicationV2) {
// #region Options
static DEFAULT_OPTIONS = {
classes: [
__ID__,
`StatsViewer`,
],
window: {
title: `Stat Viewer`,
frame: true,
positioned: true,
resizable: true,
minimizable: true,
},
position: {
width: 475,
height: 315,
},
actions: {},
};
static PARTS = {
tableSelect: {
template: filePath(`templates/Apps/StatsViewer/tableSelect.hbs`),
},
dataFilters: {
template: filePath(`templates/Apps/StatsViewer/dataFilters.hbs`),
},
graph: {
template: filePath(`templates/Apps/StatsViewer/graph.hbs`),
},
tableOverview: {
template: filePath(`templates/Apps/StatsViewer/dataOverview.hbs`),
},
};
// #endregion
async _onRender(context, options) {
await super._onRender(context, options);
const { parts } = options;
if (parts.includes(`tableSelect`)) {
this.element
.querySelector(`[data-application-part="tableSelect"] [data-bind]`)
?.addEventListener(`change`, this.#bindListener.bind(this));
};
};
async _preparePartContext(partId) {
const ctx = {};
switch (partId) {
case `tableSelect`: {
this.#prepareTableSelectContext(ctx);
break;
};
};
if (import.meta.env.DEV) {
Logger.log(`Context`, ctx);
};
return ctx;
};
_selectedTable;
_selectedSubtable;
async #prepareTableSelectContext(ctx) {
const tables = new Set();
const subtables = {};
for (const tableConfig of CONFIG.StatsDatabase.getTables()) {
const [ table, subtable ] = tableConfig.name.split(`/`);
tables.add(table);
if (subtable?.length > 0) {
subtables[table] ??= [];
subtables[table].push(subtable);
};
};
const tableList = Array.from(tables);
this._selectedTable ??= tableList[0];
ctx.table = this._selectedTable;
ctx.tables = tableList;
const subtableList = subtables[this._selectedTable];
if (subtableList && !subtableList.includes(this._selectedSubtable)) {
this._selectedSubtable = subtableList[0];
}
ctx.subtable = this._selectedSubtable;
ctx.subtables = subtableList;
};
/**
* @param {Event} event
*/
async #bindListener(event) {
const target = event.target;
const data = target.dataset;
const binding = data.bind;
if (!binding || !Object.hasOwn(this, binding)) {
return;
};
Logger.log(`updating ${binding} value to ${target.value}`);
this[binding] = target.value;
this.render();
// this.#updatePartContainingElement(target);
};
/**
* @param { HTMLElement } element
*/
#updatePartContainingElement(element) {
const partRoot = element.closest(`[data-application-part]`);
if (!partRoot) { return };
const data = partRoot.dataset;
const partId = data.applicationPart;
this.render({ parts: [partId] });
};
};

58
module/Apps/TestApp.mjs Normal file
View file

@ -0,0 +1,58 @@
import Chart from "chart.js/auto";
import { filePath } from "../consts.mjs";
const { ApplicationV2, HandlebarsApplicationMixin } = foundry.applications.api;
const data = [
{ face: 1, count: Math.floor(Math.random() * 50) },
{ face: 2, count: Math.floor(Math.random() * 50) },
{ face: 3, count: Math.floor(Math.random() * 50) },
{ face: 4, count: Math.floor(Math.random() * 50) },
{ face: 5, count: Math.floor(Math.random() * 50) },
{ face: 6, count: Math.floor(Math.random() * 50) },
];
export class TestApp extends HandlebarsApplicationMixin(ApplicationV2) {
// #region Options
static DEFAULT_OPTIONS = {
window: {
title: `Dice Pool`,
frame: true,
positioned: true,
resizable: false,
minimizable: true,
},
position: {
width: `auto`,
height: `auto`,
},
actions: {
},
};
static PARTS = {
numberOfDice: {
template: filePath(`templates/Apps/TestApp/main.hbs`),
},
};
// #endregion
_onRender() {
const canvas = this.element.querySelector(`canvas`);
new Chart(
canvas,
{
type: `bar`,
data: {
labels: data.map( r => r.face),
datasets: [
{
label: `d6 Rolls`,
data: data.map(r => r.count),
},
],
},
},
);
};
};