HASH c7456ee0b02f
DATE 2025-10-13
SUBJECT web: update simulation data
FILES 2 CHANGED
HASH c7456ee0b02f
DATE 2025-10-13
SUBJECT web: update simulation data
FILES 2 CHANGED
┌─ web/src/client/sim-chart/render/charts.ts ────────────────────────────────┐
│ diff --git a/web/src/client/sim-chart/render/charts.ts b/web/src/client/sim-chart/ │
│ render/charts.ts │
│ index e2a2c0f..b62d360 100644 │
│ --- a/web/src/client/sim-chart/render/charts.ts │
│ +++ b/web/src/client/sim-chart/render/charts.ts │
│ @@ -53,12 +53,12 @@ export function renderRankingsChartHTML( │
│ ? it.stdev │
│ : it.value; │
│ const max = Math.max(...items.map(metric), 0); │
│ - const min = Math.min(...items.map(metric), max); │
│ + const min = String(sortBy) === "dps" || String(sortBy) === "max" || String(sort │
│ By) === "min" ? 0 : Math.min(...items.map(metric), max); │
│ │
│ const bars = items │
│ .map((it, idx) => { │
│ const mval = metric(it); │
│ - const width = calculateBarWidth(mval, max, min).toFixed(1); │
│ + const width = calculateBarWidth(mval, max, min, sortBy).toFixed(1); │
│ const displayRaw = String(sortBy) === "stdev" ? it.stdev : mval; │
│ const display = Math.round(displayRaw).toLocaleString(); │
│ const tooltip = `${it.label}: ${display}`; │
│ @@ -127,21 +127,27 @@ export function renderComparisonChartHTML( │
│ barColor: string = "#666", │
│ ): string { │
│ const baseline = data?.results?.baseline?.dps || 0; │
│ + const baselineMax = data?.results?.baseline?.max || 0; │
│ + const baselineMin = data?.results?.baseline?.min || 0; │
│ const items: Item[] = []; │
│ for (const [key, v] of Object.entries<any>(data.results || {})) { │
│ if (key === "baseline") continue; │
│ + │
│ let label = key.replace(/_/g, " "); │
│ + let iconData: any = null; │
│ + let percent: number | undefined; │
│ + let dpsIncrease: number | undefined; │
│ + │
│ if (comparisonType === "race") { │
│ label = utilFormatRace(key); │
│ } │
│ - let iconData: any = null; │
│ if (comparisonType === "trinket") { │
│ iconData = trinketIconDataFromLoadout(v.loadout); │
│ if (iconData) label = iconData.ilvl ? `${iconData.ilvl}` : iconData.name; │
│ } │
│ - const percent = │
│ - baseline > 0 ? ((v.dps - baseline) / baseline) * 100 : undefined; │
│ - const dpsIncrease = baseline > 0 ? v.dps - baseline : undefined; │
│ + percent = baseline > 0 ? ((v.dps - baseline) / baseline) * 100 : undefined; │
│ + dpsIncrease = baseline > 0 ? v.dps - baseline : undefined; │
│ + │
│ (items as any).push({ │
│ label, │
│ value: v.dps, │
│ @@ -150,6 +156,8 @@ export function renderComparisonChartHTML( │
│ stdev: v.stdev, │
│ percent, │
│ dpsIncrease, │
│ + maxIncrease: baselineMax > 0 ? v.max - baselineMax : undefined, │
│ + minIncrease: baselineMin > 0 ? v.min - baselineMin : undefined, │
│ loadout: v.loadout, │
│ iconData, │
│ }); │
│ @@ -162,19 +170,19 @@ export function renderComparisonChartHTML( │
│ String(effectiveSort) === "percent" │
│ ? (it.percent ?? 0) │
│ : String(effectiveSort) === "max" │
│ - ? it.max │
│ + ? (it as any).maxIncrease ?? 0 │
│ : String(effectiveSort) === "min" │
│ - ? it.min │
│ + ? (it as any).minIncrease ?? 0 │
│ : String(effectiveSort) === "stdev" │
│ ? it.stdev │
│ - : it.value; │
│ + : (it as any).dpsIncrease ?? 0; │
│ const max = Math.max(...items.map(metric), 0); │
│ - const min = Math.min(...items.map(metric), max); │
│ + const min = String(effectiveSort) === "percent" || String(effectiveSort) === "d │
│ ps" || String(effectiveSort) === "max" || String(effectiveSort) === "min" ? 0 : Ma │
│ th.min(...items.map(metric), max); │
│ │
│ const bars = items │
│ .map((it, idx) => { │
│ const mval = metric(it); │
│ - const width = calculateBarWidth(mval, max, min).toFixed(1); │
│ + const width = calculateBarWidth(mval, max, min, effectiveSort).toFixed(1); │
│ const display = Math.round(mval).toLocaleString(); │
│ const percentStr = │
│ it.percent != null ? ` (+${it.percent.toFixed(1)}%)` : ""; │
│ @@ -187,12 +195,8 @@ export function renderComparisonChartHTML( │
│ let chartDisplay = display; │
│ let tooltip = display; │
│ if (comparisonType === "trinket" && it.percent != null) { │
│ - const percentDisplay = │
│ - it.percent === 0 ? "Baseline" : `+${it.percent.toFixed(1)}%`; │
│ - const dpsIncreaseDisplay = │
│ - (it as any).dpsIncrease === 0 │
│ - ? "Baseline" │
│ - : `+${Math.round((it as any).dpsIncrease || 0).toLocaleString()}`; │
│ + const percentDisplay = `+${it.percent.toFixed(1)}%`; │
│ + const dpsIncreaseDisplay = `+${Math.round((it as any).dpsIncrease || 0).t │
│ oLocaleString()}`; │
│ if (String(effectiveSort) === "percent") { │
│ chartDisplay = percentDisplay; │
│ tooltip = `${percentDisplay} (${display} DPS)`; │
└────────────────────────────────────────────────────────────────────────────────────┘
┌─ ...nt/sim-chart/render/charts.ts ───┐
│ diff --git a/web/src/client/sim-chart/render │
│ /charts.ts b/web/src/client/sim-chart/render │
│ /charts.ts │
│ index e2a2c0f..b62d360 100644 │
│ --- a/web/src/client/sim-chart/render/charts │
│ .ts │
│ +++ b/web/src/client/sim-chart/render/charts │
│ .ts │
│ @@ -53,12 +53,12 @@ export function renderRa │
│ nkingsChartHTML( │
│ ? it.stdev │
│ : it.value; │
│ const max = Math.max(...items.map(metric) │
│ , 0); │
│ - const min = Math.min(...items.map(metric) │
│ , max); │
│ + const min = String(sortBy) === "dps" || S │
│ tring(sortBy) === "max" || String(sortBy) == │
│ = "min" ? 0 : Math.min(...items.map(metric), │
│ max); │
│ │
│ const bars = items │
│ .map((it, idx) => { │
│ const mval = metric(it); │
│ - const width = calculateBarWidth(mval, │
│ max, min).toFixed(1); │
│ + const width = calculateBarWidth(mval, │
│ max, min, sortBy).toFixed(1); │
│ const displayRaw = String(sortBy) === │
│ "stdev" ? it.stdev : mval; │
│ const display = Math.round(displayRaw │
│ ).toLocaleString(); │
│ const tooltip = `${it.label}: ${displ │
│ ay}`; │
│ @@ -127,21 +127,27 @@ export function render │
│ ComparisonChartHTML( │
│ barColor: string = "#666", │
│ ): string { │
│ const baseline = data?.results?.baseline? │
│ .dps || 0; │
│ + const baselineMax = data?.results?.baseli │
│ ne?.max || 0; │
│ + const baselineMin = data?.results?.baseli │
│ ne?.min || 0; │
│ const items: Item[] = []; │
│ for (const [key, v] of Object.entries<any │
│ >(data.results || {})) { │
│ if (key === "baseline") continue; │
│ + │
│ let label = key.replace(/_/g, " "); │
│ + let iconData: any = null; │
│ + let percent: number | undefined; │
│ + let dpsIncrease: number | undefined; │
│ + │
│ if (comparisonType === "race") { │
│ label = utilFormatRace(key); │
│ } │
│ - let iconData: any = null; │
│ if (comparisonType === "trinket") { │
│ iconData = trinketIconDataFromLoadout │
│ (v.loadout); │
│ if (iconData) label = iconData.ilvl ? │
│ `${iconData.ilvl}` : iconData.name; │
│ } │
│ - const percent = │
│ - baseline > 0 ? ((v.dps - baseline) / │
│ baseline) * 100 : undefined; │
│ - const dpsIncrease = baseline > 0 ? v.dp │
│ s - baseline : undefined; │
│ + percent = baseline > 0 ? ((v.dps - base │
│ line) / baseline) * 100 : undefined; │
│ + dpsIncrease = baseline > 0 ? v.dps - ba │
│ seline : undefined; │
│ + │
│ (items as any).push({ │
│ label, │
│ value: v.dps, │
│ @@ -150,6 +156,8 @@ export function renderCo │
│ mparisonChartHTML( │
│ stdev: v.stdev, │
│ percent, │
│ dpsIncrease, │
│ + maxIncrease: baselineMax > 0 ? v.max │
│ - baselineMax : undefined, │
│ + minIncrease: baselineMin > 0 ? v.min │
│ - baselineMin : undefined, │
│ loadout: v.loadout, │
│ iconData, │
│ }); │
│ @@ -162,19 +170,19 @@ export function render │
│ ComparisonChartHTML( │
│ String(effectiveSort) === "percent" │
│ ? (it.percent ?? 0) │
│ : String(effectiveSort) === "max" │
│ - ? it.max │
│ + ? (it as any).maxIncrease ?? 0 │
│ : String(effectiveSort) === "min" │
│ - ? it.min │
│ + ? (it as any).minIncrease ?? 0 │
│ : String(effectiveSort) === "stde │
│ v" │
│ ? it.stdev │
│ - : it.value; │
│ + : (it as any).dpsIncrease ?? 0; │
│ const max = Math.max(...items.map(metric) │
│ , 0); │
│ - const min = Math.min(...items.map(metric) │
│ , max); │
│ + const min = String(effectiveSort) === "pe │
│ rcent" || String(effectiveSort) === "dps" || │
│ String(effectiveSort) === "max" || String(e │
│ ffectiveSort) === "min" ? 0 : Math.min(...it │
│ ems.map(metric), max); │
│ │
│ const bars = items │
│ .map((it, idx) => { │
│ const mval = metric(it); │
│ - const width = calculateBarWidth(mval, │
│ max, min).toFixed(1); │
│ + const width = calculateBarWidth(mval, │
│ max, min, effectiveSort).toFixed(1); │
│ const display = Math.round(mval).toLo │
│ caleString(); │
│ const percentStr = │
│ it.percent != null ? ` (+${it.perce │
│ nt.toFixed(1)}%)` : ""; │
│ @@ -187,12 +195,8 @@ export function renderC │
│ omparisonChartHTML( │
│ let chartDisplay = display; │
│ let tooltip = display; │
│ if (comparisonType === "trinket" && i │
│ t.percent != null) { │
│ - const percentDisplay = │
│ - it.percent === 0 ? "Baseline" : ` │
│ +${it.percent.toFixed(1)}%`; │
│ - const dpsIncreaseDisplay = │
│ - (it as any).dpsIncrease === 0 │
│ - ? "Baseline" │
│ - : `+${Math.round((it as any).dp │
│ sIncrease || 0).toLocaleString()}`; │
│ + const percentDisplay = `+${it.perce │
│ nt.toFixed(1)}%`; │
│ + const dpsIncreaseDisplay = `+${Math │
│ .round((it as any).dpsIncrease || 0).toLocal │
│ eString()}`; │
│ if (String(effectiveSort) === "perc │
│ ent") { │
│ chartDisplay = percentDisplay; │
│ tooltip = `${percentDisplay} (${d │
│ isplay} DPS)`; │
└──────────────────────────────────────────────┘
┌─ web/src/client/sim-chart/sorting.ts ──────────────────────────────────────┐
│ diff --git a/web/src/client/sim-chart/sorting.ts b/web/src/client/sim-chart/sortin │
│ g.ts │
│ index 9727f4f..269c6dc 100644 │
│ --- a/web/src/client/sim-chart/sorting.ts │
│ +++ b/web/src/client/sim-chart/sorting.ts │
│ @@ -1,18 +1,9 @@ │
│ export type SortBy = "dps" | "max" | "min" | "stdev" | "percent" | string; │
│ │
│ -export function calculateBarWidth(value: number, max: number, min: number) { │
│ - if (max <= 0) return 0; │
│ - // Hybrid scaling with minimum visibility │
│ - const valueRange = Math.max(max - min, 0); │
│ - const average = (max + min) / 2 || max; │
│ - const cov = average ? valueRange / average : 0; │
│ - const rangeWeight = Math.min(cov * 1.5, 0.8); │
│ - const zeroWeight = 1 - rangeWeight; │
│ - const zeroPct = max ? value / max : 0; │
│ - const rangePct = valueRange > 0 ? (value - min) / valueRange : 1; │
│ - const pct = zeroPct * zeroWeight + rangePct * rangeWeight; │
│ - const minPct = 0.15; │
│ - return Math.max(pct, minPct) * 100; │
│ +export function calculateBarWidth(value: number, max: number, min: number, sortBy │
│ ?: SortBy) { │
│ + const valueRange = max - min; │
│ + if (valueRange <= 0) return 100; │
│ + return ((value - min) / valueRange) * 100; │
│ } │
│ │
│ export type ItemForSort = { │
└────────────────────────────────────────────────────────────────────────────────────┘
┌─ ...c/client/sim-chart/sorting.ts ───┐
│ diff --git a/web/src/client/sim-chart/sortin │
│ g.ts b/web/src/client/sim-chart/sorting.ts │
│ index 9727f4f..269c6dc 100644 │
│ --- a/web/src/client/sim-chart/sorting.ts │
│ +++ b/web/src/client/sim-chart/sorting.ts │
│ @@ -1,18 +1,9 @@ │
│ export type SortBy = "dps" | "max" | "min" │
│ | "stdev" | "percent" | string; │
│ │
│ -export function calculateBarWidth(value: nu │
│ mber, max: number, min: number) { │
│ - if (max <= 0) return 0; │
│ - // Hybrid scaling with minimum visibility │
│ - const valueRange = Math.max(max - min, 0) │
│ ; │
│ - const average = (max + min) / 2 || max; │
│ - const cov = average ? valueRange / averag │
│ e : 0; │
│ - const rangeWeight = Math.min(cov * 1.5, 0 │
│ .8); │
│ - const zeroWeight = 1 - rangeWeight; │
│ - const zeroPct = max ? value / max : 0; │
│ - const rangePct = valueRange > 0 ? (value │
│ - min) / valueRange : 1; │
│ - const pct = zeroPct * zeroWeight + rangeP │
│ ct * rangeWeight; │
│ - const minPct = 0.15; │
│ - return Math.max(pct, minPct) * 100; │
│ +export function calculateBarWidth(value: nu │
│ mber, max: number, min: number, sortBy?: Sor │
│ tBy) { │
│ + const valueRange = max - min; │
│ + if (valueRange <= 0) return 100; │
│ + return ((value - min) / valueRange) * 100 │
│ ; │
│ } │
│ │
│ export type ItemForSort = { │
└──────────────────────────────────────────────┘
[ BACK TO LOG ]
──────────────────────────────────────────────────────────────────────────────────────
OOKNET
────────────────────────────────────────────────
OOKNET