Skip to content

Commit

Permalink
fix(rum-explorer): use common number formatting in sidebar
Browse files Browse the repository at this point in the history
  • Loading branch information
trieloff committed Jun 24, 2024
1 parent 23b3858 commit 9cf4a11
Show file tree
Hide file tree
Showing 4 changed files with 93 additions and 25 deletions.
35 changes: 20 additions & 15 deletions tools/rum/elements/list-facet.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {
computeConversionRate, escapeHTML, scoreCWV, toHumanReadable,
computeConversionRate, escapeHTML, scoreCWV,
} from '../utils.js';
import { tTest, zTestTwoProportions } from '../cruncher.js';

Expand Down Expand Up @@ -72,19 +72,19 @@ export default class ListFacet extends HTMLElement {
let lcp = '-';
if (entry.metrics.lcp && entry.metrics.lcp.count >= CWVDISPLAYTHRESHOLD) {
const lcpValue = entry.metrics.lcp.percentile(75);
lcp = `${toHumanReadable(lcpValue / 1000)} s`;
lcp = `${(lcpValue / 1000)} s`;
}

let cls = '-';
if (entry.metrics.cls && entry.metrics.cls.count >= CWVDISPLAYTHRESHOLD) {
const clsValue = entry.metrics.cls.percentile(75);
cls = `${toHumanReadable(clsValue)}`;
cls = `${(clsValue)}`;
}

let inp = '-';
if (entry.metrics.inp && entry.metrics.inp.count >= CWVDISPLAYTHRESHOLD) {
const inpValue = entry.metrics.inp.percentile(75);
inp = `${toHumanReadable(inpValue / 1000)} s`;
inp = `${(inpValue / 1000)} s`;
}

tsv.push(`${entry.value}\t${entry.metrics.pageViews.sum}\t${lcp}\t${cls}\t${inp}`);
Expand Down Expand Up @@ -219,13 +219,15 @@ export default class ListFacet extends HTMLElement {

const label = document.createElement('label');
label.setAttribute('for', `${facetName}-${entry.value}`);
const countspan = document.createElement('span');
const countspan = document.createElement('number-format');
countspan.className = 'count';
countspan.textContent = toHumanReadable(entry.metrics.pageViews.sum);
countspan.title = entry.metrics.pageViews.sum;
countspan.textContent = entry.metrics.pageViews.sum;
countspan.setAttribute('sample-size', entry.metrics.pageViews.count);
countspan.setAttribute('total', this.dataChunks.totals.pageViews.sum);
countspan.setAttribute('fuzzy', 'false');
const valuespan = this.createValueSpan(entry);

const conversionspan = document.createElement('span');
const conversionspan = document.createElement('number-format');
conversionspan.className = 'extra';

// we need to divide the totals by average weight
Expand All @@ -244,8 +246,8 @@ export default class ListFacet extends HTMLElement {
const conversions = entry.metrics.conversions.sum;
const visits = entry.metrics.visits.sum;
const conversionRate = computeConversionRate(conversions, visits);
conversionspan.textContent = toHumanReadable(conversionRate);
conversionspan.title = entry.metrics.conversions.sum;
conversionspan.textContent = conversionRate;
conversionspan.setAttribute('precision', 2);

label.append(valuespan, countspan, conversionspan);

Expand Down Expand Up @@ -347,22 +349,25 @@ export default class ListFacet extends HTMLElement {
let cwv = '-';
let score = '';
const li = document.createElement('li');
const nf = document.createElement('number-format');
nf.setAttribute('precision', 2);
nf.setAttribute('fuzzy', 'false');
const fillEl = async () => {
li.title = metricName.toUpperCase();
if (entry.metrics[metricName] && entry.metrics[metricName].count >= CWVDISPLAYTHRESHOLD) {
const value = entry.metrics[metricName].percentile(75);
cwv = `${toHumanReadable(value / (metricName === 'cls' ? 1 : 1000))}`;
if (metricName === 'inp' || metricName === 'lcp') {
cwv += ' s';
}
cwv = metricName !== 'cls'
? value / 1000
: (Math.round(value * 100) / 100);
nf.textContent = cwv;
score = scoreCWV(value, metricName);
addSignificanceFlag(li, entry.metrics[metricName], this.dataChunks.totals[metricName]);
li.title += ` - based on ${entry.metrics[metricName].count} samples`;
} else {
li.title += ` - not enough samples (${entry.metrics[metricName].count})`;
}
li.classList.add(`score-${score}`);
li.textContent = cwv;
li.append(nf);
};
// fill the element, but don't wait for it
fillEl();
Expand Down
20 changes: 11 additions & 9 deletions tools/rum/rum-slicer.css
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,9 @@ main .key-metrics ul > #visits p .extra::after {
}

main .key-metrics ul > #lcp p number-format::after,
main .key-metrics ul > #inp p number-format::after{
main .key-metrics ul > #inp p number-format::after,
main facet-sidebar ul.cwv > li[title^="LCP"] number-format::after,
main facet-sidebar ul.cwv > li[title^="INP"] number-format::after {
content: 's';
}

Expand Down Expand Up @@ -573,29 +575,29 @@ vitals-facet label::before {
word-break: break-all;
}

#facets fieldset label span.count, #facets fieldset label span.extra {
#facets fieldset label .count, #facets fieldset label .extra {
opacity: 0.6;
}

#facets fieldset div:hover span.count, #facets fieldset div:hover span.extra {
#facets fieldset div:hover .count, #facets fieldset div:hover .extra {
opacity: 1;
}

#facets fieldset label span.extra {
#facets fieldset label .extra {
display: none;
}

#facets fieldset label span.extra.interesting {
#facets fieldset label .extra.interesting {
display: inline;
opacity: 0.8;
}

#facets fieldset label span.extra.significant {
#facets fieldset label .extra.significant {
display: inline;
opacity: 0.9;
}

#facets fieldset label span.count::before,
#facets fieldset label .count::before,
#facets fieldset label span.value::before {
content: ' (';
}
Expand All @@ -604,11 +606,11 @@ vitals-facet label::before {
content: '';
}

#facets fieldset label span.count::after, #facets fieldset label span.value::after {
#facets fieldset label .count::after, #facets fieldset label span.value::after {
content: ') ';
}

#facets fieldset label span.extra::after {
#facets fieldset label .extra::after {
content: '% conversion rate';
}

Expand Down
58 changes: 58 additions & 0 deletions tools/rum/test/number-format.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import { describe, it } from 'node:test';
import assert from 'node:assert/strict';
import { roundToConfidenceInterval, samplingError } from '../utils.js';

describe('samplingError', () => {
it('computes the sampling error', () => {
assert.strictEqual(samplingError(60, 10), 37);
assert.strictEqual(samplingError(600, 100), 118);
assert.strictEqual(samplingError(300, 100), 59);
assert.strictEqual(samplingError(30, 10), 19);
});
});

describe('number-format', () => {
it('uses exponents', () => {
assert.strictEqual(roundToConfidenceInterval(100), '100');
assert.strictEqual(roundToConfidenceInterval(1000), '1k');
assert.strictEqual(roundToConfidenceInterval(10000), '10k');
assert.strictEqual(roundToConfidenceInterval(100000), '100k');
assert.strictEqual(roundToConfidenceInterval(1000000), '1m');
assert.strictEqual(roundToConfidenceInterval(10000000), '10m');
assert.strictEqual(roundToConfidenceInterval(100000000), '100m');
assert.strictEqual(roundToConfidenceInterval(1000000000), '1g');
assert.strictEqual(roundToConfidenceInterval(10000000000), '10g');
assert.strictEqual(roundToConfidenceInterval(100000000000), '100g');
assert.strictEqual(roundToConfidenceInterval(1000000000000), '1t');
assert.strictEqual(roundToConfidenceInterval(10000000000000), '10t');
assert.strictEqual(roundToConfidenceInterval(100000000000000), '100t');
assert.strictEqual(roundToConfidenceInterval(1000000000000000), '1p');
assert.strictEqual(roundToConfidenceInterval(10000000000000000), '10p');
assert.strictEqual(roundToConfidenceInterval(100000000000000000), '100p');
assert.strictEqual(roundToConfidenceInterval(1000000000000000000), '1,000p');
assert.strictEqual(roundToConfidenceInterval(10000000000000000000), '10,000p');
});

it('supports decimal places', () => {
assert.strictEqual(roundToConfidenceInterval(1500), '1.5k');
assert.strictEqual(roundToConfidenceInterval(15000), '15k');
assert.strictEqual(roundToConfidenceInterval(150000), '150k');
assert.strictEqual(roundToConfidenceInterval(1500000), '1.5m');
});

it('curbs precision according to sample size', () => {
assert.strictEqual(roundToConfidenceInterval(31415, 30), '31k');
assert.strictEqual(roundToConfidenceInterval(3141592, 300), '3.1m');
assert.strictEqual(roundToConfidenceInterval(314159265, 3000), '310m');
// when accuracy is getting fuzzy, we switch to fractional notation
assert.strictEqual(roundToConfidenceInterval(3141592653, 30), '3⅛g');
assert.strictEqual(roundToConfidenceInterval(
3141592653,
300000,
), '3.142g');
assert.strictEqual(roundToConfidenceInterval(
3141592653,
3000,
), '3.1g');
});
});
5 changes: 4 additions & 1 deletion tools/rum/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -282,7 +282,10 @@ export function roundToConfidenceInterval(
}
return acc;
}, 0), Number.isNaN(maxPrecision) ? Infinity : maxPrecision);
const precision = Math.max(2, common);
const precision = Math.max(
Math.min(2, maxPrecision),
common,
);
// we don't want to show too many zeros, so we use k, m, g, etc.
const exponentSuffixes = ['k', 'm', 'g', 't', 'p'];
const { value, exponent } = exponentSuffixes.reduce((acc, suffix) => {
Expand Down

0 comments on commit 9cf4a11

Please sign in to comment.