Website: machine estimator v3 — the bar shows what the box's memory is used for (still unlisted, R-997)
gates / gates (push) Successful in 6m29s
gates / gates (push) Successful in 6m29s
The bar keeps its length (the fits-well box memory) and is split into base system (box - guest), Felhom's own services, each app's peak (largest first, the dashboard's palette minus amber and its first blue; beyond 8 apps one group) and spare room (guest - peak) — all from the one rule; a test proves the parts sum to the bar within 1 MB. A legend under it (not sticky) and one sentence explain the recommended size. Typical figure moved into the method fold-out. English: 'an 8 GB machine'.
This commit is contained in:
+77
-19
@@ -11,7 +11,10 @@
|
||||
* tight peak <= guest < peak * headroom
|
||||
* no guest < peak
|
||||
* the memory bar: minBoxGb() inverts guestMib() by SEARCHING it — the smallest box memory whose guest
|
||||
* holds peak * headroom (solid fill) and peak (thin marker). It never restates the installer's rule.
|
||||
* holds peak * headroom (the bar's length) and peak (thin marker). It never restates the installer's rule.
|
||||
* v3: the bar is split into what that box memory is used for, every part from the same rule:
|
||||
* base system = box - guest(box) · Felhom = platform · each app = its peak · spare = guest(box) - peak
|
||||
* so the parts add up to the box exactly (scripts/test_build_sizing_web.py proves it).
|
||||
*
|
||||
* The page text is not here: each page carries its own strings (#sizer-strings), so this file is the
|
||||
* same for both languages.
|
||||
@@ -64,10 +67,19 @@
|
||||
if (tightBox === null && b.verdict === 'tight') { tightBox = b.gb; }
|
||||
});
|
||||
var heavy = busy.filter(function (a) { return a.cpu_class === 'heavy-in-bursts'; });
|
||||
var wellGb = minBoxGb(data, peak * data.headroom);
|
||||
var boxMb = wellGb * 1024, guestMb = guestMib(data, wellGb);
|
||||
var apps = slugs.map(function (s) { return bySlug[s]; })
|
||||
.filter(function (a) { return a && !a.builtin; })
|
||||
.sort(function (x, y) { return y.peak_mb - x.peak_mb; });
|
||||
var segments = [{ kind: 'base', mb: boxMb - guestMb }, { kind: 'platform', mb: data.platform_mb }];
|
||||
apps.forEach(function (a) { segments.push({ kind: 'app', app: a, mb: a.peak_mb }); });
|
||||
segments.push({ kind: 'spare', mb: guestMb - peak });
|
||||
return {
|
||||
typical_mb: typical, peak_mb: peak, boxes: boxes, busy: busy, heavy: heavy, unmeasured: unmeasured,
|
||||
well_gb: minBoxGb(data, peak * data.headroom), tight_gb: minBoxGb(data, peak),
|
||||
recommend_gb: recommend, tight_box_gb: tightBox
|
||||
well_gb: wellGb, tight_gb: minBoxGb(data, peak),
|
||||
recommend_gb: recommend, tight_box_gb: tightBox,
|
||||
segments: segments, base_mb: boxMb - guestMb, apps_peak_mb: peak - data.platform_mb
|
||||
};
|
||||
}
|
||||
|
||||
@@ -106,6 +118,13 @@
|
||||
var meter = document.getElementById('sizer-meter');
|
||||
var line = document.getElementById('sizer-line');
|
||||
var result = document.getElementById('sizer-result');
|
||||
var stack = document.getElementById('sizer-stack');
|
||||
var legend = document.getElementById('sizer-legend');
|
||||
var why = document.getElementById('sizer-why-line');
|
||||
var typicalLine = document.getElementById('sizer-typical');
|
||||
// English needs "an 8 GB machine"; the article comes from the page's strings (none in Hungarian)
|
||||
var article = function (gb) { return (T.an_before || []).indexOf(String(gb)) !== -1 ? T.an : T.a; };
|
||||
var fill = function (tpl, gb) { return tpl.replace('{a}', article(gb) || '').replace('{gb}', gb); };
|
||||
|
||||
fetch(host.getAttribute('data-src')).then(function (r) { return r.json(); }).then(function (data) {
|
||||
var max = data.bar_max_gb;
|
||||
@@ -160,11 +179,44 @@
|
||||
g.count.textContent = n ? T.selected.replace('{n}', n) : '';
|
||||
});
|
||||
|
||||
// the bar: solid fill = fits well, thin marker = fits, but tight
|
||||
var wellPct = Math.min(r.well_gb / max, 1) * 100;
|
||||
var tightPct = Math.min(r.tight_gb / max, 1) * 100;
|
||||
document.getElementById('sizer-fill').style.width = wellPct + '%';
|
||||
document.getElementById('sizer-tight').style.left = tightPct + '%';
|
||||
// the bar: its length is the "fits well" box memory, split into what that memory is used for
|
||||
// (estimate().segments); beyond the colour count the smallest apps join one segment
|
||||
var basis = Math.max(r.well_gb, max) * 1024;
|
||||
var segs = [], rest = { kind: 'more', mb: 0, n: 0 }, nApps = 0;
|
||||
r.segments.forEach(function (sg) {
|
||||
if (sg.kind === 'app') {
|
||||
nApps += 1;
|
||||
if (nApps > data.bar_app_colours) { rest.mb += sg.mb; rest.n += 1; return; }
|
||||
sg.colour = 'sizer-c' + nApps;
|
||||
}
|
||||
if (sg.kind === 'spare' && rest.n) { segs.push(rest); }
|
||||
segs.push(sg);
|
||||
});
|
||||
var label = function (sg) {
|
||||
if (sg.kind === 'app') { return lang === 'en' ? sg.app.name_en : sg.app.name_hu; }
|
||||
if (sg.kind === 'more') { return T.seg_more.replace('{n}', sg.n); }
|
||||
return T['seg_' + sg.kind];
|
||||
};
|
||||
stack.textContent = '';
|
||||
legend.textContent = '';
|
||||
segs.forEach(function (sg) {
|
||||
var cls = sg.kind === 'app' ? sg.colour : 'sizer-seg-' + sg.kind;
|
||||
var part = el('div', 'sizer-seg ' + cls);
|
||||
part.style.width = (sg.mb / basis * 100) + '%';
|
||||
part.title = label(sg) + ': ' + Math.round(sg.mb) + ' MB';
|
||||
stack.appendChild(part);
|
||||
var li = el('li', 'sizer-legend-item');
|
||||
li.appendChild(el('span', 'sizer-dot ' + cls));
|
||||
li.appendChild(el('span', '', label(sg) + ' '));
|
||||
li.appendChild(el('span', 'sizer-num', gbText(sg.mb)));
|
||||
legend.appendChild(li);
|
||||
});
|
||||
var tli = el('li', 'sizer-legend-item');
|
||||
tli.appendChild(el('span', 'sizer-dot sizer-seg-tightmark'));
|
||||
tli.appendChild(el('span', '', T.seg_tight + ' '));
|
||||
tli.appendChild(el('span', 'sizer-num', dec(r.tight_gb) + ' GB'));
|
||||
legend.appendChild(tli);
|
||||
document.getElementById('sizer-tight').style.left = (Math.min(r.tight_gb / max, 1) * 100) + '%';
|
||||
var over = r.well_gb > max;
|
||||
var needText = over ? T.over_max.replace('{gb}', max) : dec(r.well_gb) + ' GB';
|
||||
meter.setAttribute('aria-valuenow', String(Math.min(r.well_gb, max).toFixed(1)));
|
||||
@@ -173,23 +225,29 @@
|
||||
// one line: which box to buy, and where it is tight
|
||||
var biggest = data.boxes_gb[data.boxes_gb.length - 1];
|
||||
if (r.recommend_gb !== null) {
|
||||
line.textContent = T.recommend.replace('{gb}', r.recommend_gb) +
|
||||
(r.tight_box_gb !== null ? ' ' + T.tight_on.replace('{gb}', r.tight_box_gb) : '');
|
||||
line.textContent = fill(T.recommend, r.recommend_gb) +
|
||||
(r.tight_box_gb !== null ? ' ' + fill(T.tight_on, r.tight_box_gb) : '');
|
||||
} else if (r.tight_box_gb !== null) {
|
||||
line.textContent = T.only_tight.replace('{gb}', r.tight_box_gb);
|
||||
line.textContent = fill(T.only_tight, r.tight_box_gb);
|
||||
} else {
|
||||
line.textContent = T.none_fits.replace('{gb}', biggest);
|
||||
line.textContent = fill(T.none_fits, biggest);
|
||||
}
|
||||
|
||||
// under the bar: totals, why tight is tight, the CPU lines
|
||||
result.textContent = '';
|
||||
var totals = el('p', 'sizer-totals');
|
||||
totals.appendChild(el('span', '', T.typical + ': '));
|
||||
totals.appendChild(el('strong', 'sizer-num', gbText(r.typical_mb)));
|
||||
totals.appendChild(el('span', '', ' · ' + T.peak + ': '));
|
||||
totals.appendChild(el('strong', 'sizer-num', gbText(r.peak_mb)));
|
||||
result.appendChild(totals);
|
||||
result.appendChild(el('p', 'sizer-fine', T.platform_note));
|
||||
// the explaining sentence: three numbers, all from the rule; bold parts are {b}…{/b}
|
||||
why.textContent = '';
|
||||
var tpl = r.apps_peak_mb > 0
|
||||
? (r.recommend_gb !== null ? T.why : T.why_over)
|
||||
: T.why_empty;
|
||||
var spare = Math.round((data.headroom - 1) * 100);
|
||||
tpl.replace('{peak}', dec(r.peak_mb / 1024)).replace('{base}', dec(r.base_mb / 1024))
|
||||
.replace('{base_platform}', dec((r.base_mb + data.platform_mb) / 1024))
|
||||
.replace('{spare}', spare).replace('{rec}', r.recommend_gb === null ? max : r.recommend_gb)
|
||||
.split(/\{b\}|\{\/b\}/).forEach(function (part, i) {
|
||||
why.appendChild(i % 2 ? el('strong', 'sizer-num', part) : document.createTextNode(part));
|
||||
});
|
||||
typicalLine.textContent = T.typical_line.replace('{typical}', gbText(r.typical_mb)).replace('{peak}', gbText(r.peak_mb));
|
||||
if (r.tight_box_gb !== null) { result.appendChild(el('p', 'sizer-why', T.tight_why)); }
|
||||
|
||||
if (r.busy.length) {
|
||||
|
||||
Reference in New Issue
Block a user