Get the graph rendering as expected

This commit is contained in:
Oliver-Akins 2025-04-23 00:16:24 -06:00
parent 3796687a72
commit 5e9b91b199
5 changed files with 98 additions and 24 deletions

View file

@ -1,5 +1,7 @@
import { Chart } from "chart.js";
import { filePath } from "../consts.mjs";
import { Logger } from "../utils/Logger.mjs";
import { smallToLarge } from "../utils/sorters/smallToLarge.mjs";
const { HandlebarsApplicationMixin, ApplicationV2 } = foundry.applications.api;
@ -19,7 +21,7 @@ export class StatsViewer extends HandlebarsApplicationMixin(ApplicationV2) {
},
position: {
width: 475,
height: 315,
height: 400,
},
actions: {},
};
@ -55,6 +57,11 @@ export class StatsViewer extends HandlebarsApplicationMixin(ApplicationV2) {
for (const input of elements) {
input.addEventListener(`change`, this.#bindListener.bind(this));
};
if (options.parts.includes(`graph`)) {
const canvas = this.element.querySelector(`canvas`);
new Chart( canvas, this._graphData );
};
};
async _preparePartContext(partId) {
@ -126,22 +133,76 @@ export class StatsViewer extends HandlebarsApplicationMixin(ApplicationV2) {
_graphData = {};
async #prepareGraphContext(_ctx) {
const datasets = CONFIG.StatsDatabase.getRows(
const userData = CONFIG.StatsDatabase.getRows(
`${this._selectedTable}/${this._selectedSubtable}`,
this._selectedUsers,
);
Logger.log(datasets);
const data = {};
const allBuckets = new Set();
const buckets = {};
for (const row of datasets[game.user.id] ?? []) {
buckets[row.value] ??= 0;
buckets[row.value] += 1;
/*
When we're displaying data for a table within the Dice namespace, we want to
include all values that any user might not have rolled, just for completeness
since we do know exactly what labels to display, this might eventually be
replaced with a per-table configuration setting to determine what values are
populated within the graph and nothing else / prevent non-accepted values
from being added to the table in the first place.
*/
if (this._selectedTable === `Dice`) {
const size = Number.parseInt(this._selectedSubtable.slice(1));
for (let i = 1; i <= size; i++) {
allBuckets.add(i);
};
};
const sorted = Object.entries(buckets).sort(([v1], [v2]) => Math.sign(v1 - v2));
for (const user of this._selectedUsers) {
const buckets = {};
for (const row of userData[user] ?? []) {
buckets[row.value] ??= 0;
buckets[row.value] += 1;
allBuckets.add(row.value);
};
data[user] = buckets;
}
Logger.log(sorted);
const sortedBucketNames = Array.from(allBuckets).sort(smallToLarge);
const datasets = {};
for (const bucket of sortedBucketNames) {
for (const user of this._selectedUsers) {
datasets[user] ??= [];
datasets[user].push(data[user][bucket]);
};
};
this._graphData = {
type: `bar`,
options: {
scales: {
y: {
stacked: true,
},
x: {
stacked: true,
},
},
},
data: {
labels: sortedBucketNames,
datasets: Object.entries(datasets).map(([userID, values]) => {
const user = game.users.get(userID);
return {
label: user.name,
data: values,
borderColor: user.color.css,
backgroundColor: user.color.toRGBA(0.5),
borderWidth: 2,
borderRadius: 4,
borderSkipped: false,
};
}),
},
};
};
/**
@ -160,17 +221,5 @@ export class StatsViewer extends HandlebarsApplicationMixin(ApplicationV2) {
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] });
};
};

View file

@ -52,13 +52,17 @@ export class MemoryDatabase {
if (!subtable) {
continue;
}
const size = Number.parseInt(subtable.slice(1));
const rows = [];
for (let i = 1; i <= size; i++) {
const count = getNormalDistributionHeight(i, size / 2, size);
console.table({ count, i });
const temp = new Array(count).fill(null).map(() => generateRow(i));
const temp = new Array(count)
.fill(null)
.map(() => generateRow(
game.user.id == user ? i : Math.ceil(Math.random() * size),
));
rows.push(...temp);
};

View file

@ -0,0 +1,19 @@
/**
*
* @param {string | number} a
* @param {string | number} b
*/
export function smallToLarge(a, b) {
const aInt = Number.parseInt(a);
const bInt = Number.parseInt(b);
const aIsInvalid = Number.isNaN(aInt);
const bIsInvalid = Number.isNaN(bInt);
if (aIsInvalid && bIsInvalid) {
return a > b;
} else if (aIsInvalid || bIsInvalid) {
return aIsInvalid ? -1 : 1;
};
return Math.sign(aInt - bInt);
};

View file

@ -17,5 +17,7 @@
[data-application-part="graph"] {
flex-grow: 1;
justify-items: center;
position: relative;
}
}

View file

@ -1,3 +1,3 @@
<div>
Graph Canvas
<canvas></canvas>
</div>