Мінікарта малює справжні літери, а не прямокутники
Скільки не підбирай товщину, колір і щільність — прямокутник не стає літерою. Арифметика: щоб текст читався, символу треба 5-6 пікселів; при 120 символах у смузі 180 px виходило 1.4. Читабельним він не міг стати за жодних налаштувань, і три попередні спроби це лікували симптоматично. Тепер canvas друкує ПОЧАТОК рядка шрифтом 7 px — найменшим, на якому моноширинний ще лишається літерами (на 6 зникають внутрішні просвіти в e, a, o). Ширина символа вимірюється, а не рахується формулою: у різних системах підставляється різний моноширинний шрифт. Для конфігу початок рядка й несе структуру: відступ і ключове слово стоять зліва, а хвіст з адресами не читався б однаково. Табуляція розгортається в пробіли — у canvas вона не має ширини, і блоки JunOS з їхали б до лівого краю. Рядків у вікні стало близько вісімдесяти замість двохсот. Це обмін, а не втрата: двісті нечитабельних показують силует файла, вісімдесят читабельних показують, ДЕ ти в ньому. Запасний шлях прямокутниками лишився для порівняння версій, де рядки беруться з різниці, а не з файла.
This commit is contained in:
parent
3a52d4a870
commit
68fd47ff19
1 changed files with 42 additions and 28 deletions
|
|
@ -79,7 +79,22 @@ export const MAP_W = 180
|
||||||
* Розмін свідомий: мініатюра, на якій нічого не розібрати, не стає
|
* Розмін свідомий: мініатюра, на якій нічого не розібрати, не стає
|
||||||
* кориснішою від того, що вміщає більше.
|
* кориснішою від того, що вміщає більше.
|
||||||
*/
|
*/
|
||||||
const ROW_PX = 3
|
const ROW_PX = 8
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Розмір шрифту мініатюри.
|
||||||
|
*
|
||||||
|
* Сім пікселів — найменше, на чому моноширинний шрифт ще лишається
|
||||||
|
* ЛІТЕРАМИ, а не сірою крупою. Менше пробували: на шести зникають
|
||||||
|
* внутрішні просвіти в «e», «a», «o», і слово перетворюється на пляму
|
||||||
|
* тієї самої довжини.
|
||||||
|
*
|
||||||
|
* Звідси й ROW_PX = 8: сім на літери, один на просвіт між рядками.
|
||||||
|
* Рядків у вікні стає близько вісімдесяти замість двохсот — і це не
|
||||||
|
* втрата, а обмін. Двісті нечитабельних рядків показують силует файла;
|
||||||
|
* вісімдесят читабельних показують, ДЕ ти в ньому. Друге і просили.
|
||||||
|
*/
|
||||||
|
const FONT_PX = 7
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Товщина штриха рядка. Один піксель, а не два — і це не косметика.
|
* Товщина штриха рядка. Один піксель, а не два — і це не косметика.
|
||||||
|
|
@ -125,21 +140,6 @@ const GUTTER_W = 6
|
||||||
*/
|
*/
|
||||||
const MAX_COLS = 120
|
const MAX_COLS = 120
|
||||||
|
|
||||||
/**
|
|
||||||
* Скільки слів у рядку малюємо окремо.
|
|
||||||
*
|
|
||||||
* Саме проміжки між словами роблять смужку схожою на текст: суцільна
|
|
||||||
* риса від відступу до кінця рядка читається як штрих, а не як рядок.
|
|
||||||
*
|
|
||||||
* Стеля потрібна, бо в конфігах трапляються рядки на сотні коротких
|
|
||||||
* лексем (списки VLAN, префікс-листи): малювати їх усі — це тисячі
|
|
||||||
* прямокутників заради ділянки в кілька пікселів завширшки.
|
|
||||||
*/
|
|
||||||
const MAX_SEGS = 40
|
|
||||||
|
|
||||||
const SP = ' '
|
|
||||||
const TAB = ' '
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Форма тексту: довжина й відступ кожного рядка.
|
* Форма тексту: довжина й відступ кожного рядка.
|
||||||
*
|
*
|
||||||
|
|
@ -384,6 +384,25 @@ export function Minimap({
|
||||||
ctx.clearRect(0, 0, MAP_W, h)
|
ctx.clearRect(0, 0, MAP_W, h)
|
||||||
|
|
||||||
const left = fits ? 3 : GUTTER_W + 3
|
const left = fits ? 3 : GUTTER_W + 3
|
||||||
|
|
||||||
|
// Справжній текст замість штрихів.
|
||||||
|
//
|
||||||
|
// Попередні версії малювали слова прямокутниками — і скільки не
|
||||||
|
// підбирай товщину, колір і щільність, прямокутник не стає літерою.
|
||||||
|
// Арифметика проста: щоб текст читався, символу треба 5–6 пікселів;
|
||||||
|
// при 120 символах у смузі 180 px виходило 1.4, тобто читабельним
|
||||||
|
// він не міг стати за жодних налаштувань.
|
||||||
|
//
|
||||||
|
// Тому показуємо ПОЧАТОК рядка справжніми літерами. Для конфігу це
|
||||||
|
// саме те, що несе структуру: відступ і ключове слово стоять зліва,
|
||||||
|
// а хвіст із адресами й масками не читався б однаково.
|
||||||
|
ctx.font = FONT_PX + 'px ui-monospace, SFMono-Regular, Menlo, Consolas, monospace'
|
||||||
|
ctx.textBaseline = 'top'
|
||||||
|
// Ширину символа беремо вимірюванням, а не формулою: у різних
|
||||||
|
// системах підставляється різний моноширинний шрифт, і константа
|
||||||
|
// тут рано чи пізно розійшлася б із дійсністю мовчки.
|
||||||
|
const charW = ctx.measureText('0').width || FONT_PX * 0.6
|
||||||
|
const maxChars = Math.max(1, Math.floor((MAP_W - left - 3) / charW))
|
||||||
const scale = (MAP_W - left - 3) / cols
|
const scale = (MAP_W - left - 3) / cols
|
||||||
|
|
||||||
// У режимі «влазить цілком» рядку дістається стільки пікселів,
|
// У режимі «влазить цілком» рядку дістається стільки пікселів,
|
||||||
|
|
@ -411,24 +430,19 @@ export function Minimap({
|
||||||
ctx.fillStyle = color
|
ctx.fillStyle = color
|
||||||
|
|
||||||
// Без доступу до самого тексту лишається суцільна риса від
|
// Без доступу до самого тексту лишається суцільна риса від
|
||||||
// відступу до кінця рядка. Працює, але читається гірше.
|
// відступу до кінця рядка. Це запасний шлях: ним іде порівняння
|
||||||
|
// версій, де рядки беруться не з файла, а з різниці.
|
||||||
const text = lineAt?.(i)
|
const text = lineAt?.(i)
|
||||||
if (!text) {
|
if (!text) {
|
||||||
bar(shape.indent[i], L, y)
|
bar(shape.indent[i], L, y)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
let j = 0
|
// Табуляція в canvas не має ширини — розгортаємо в пробіли, інакше
|
||||||
let segs = 0
|
// блоки JunOS з'їхали б до лівого краю й структура зникла саме
|
||||||
while (j < text.length && segs < MAX_SEGS) {
|
// там, де вона найпомітніша.
|
||||||
while (j < text.length && (text[j] === SP || text[j] === TAB)) j++
|
const flat = text.length > maxChars * 2 ? text.slice(0, maxChars * 2) : text
|
||||||
const a = j
|
ctx.fillText(flat.replace(/ /g, ' ').slice(0, maxChars), left, y)
|
||||||
while (j < text.length && text[j] !== SP && text[j] !== TAB) j++
|
|
||||||
if (j > a) {
|
|
||||||
bar(a, j, y)
|
|
||||||
segs++
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fits) {
|
if (fits) {
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue