test-task-treerender
85 строк · 4.4 Кб
1/**
2* Функция для создания элементов дерева
3* @param {{value: string, level: number, index: number}[]} nodes - Исходная строка, пример: (1 (2 (4 5 6 (7) 108 (9)) 3))
4*/
5export function createTree(nodes) {6let tree = ``; // Дерево7const maxValuesLengthOnLevel = []; // Массив из максимальных количеств символов числа на каждом уровне8const verticalLinePositions = []; // Текущии позиции вертикальных линий в строке9const levels = Array.from(new Set(nodes.map((item) => item.level))); // Все уровни из исходных данных10
11// Получаем максимальные количеств символов числа на каждом уровне12for (let i = 0; i < levels.length; i++) {13const value = nodes14.filter((item) => item.level === levels[i])15.map((item) => item.value)16.sort((a, b) => b.length - a.length)[0].length;17
18maxValuesLengthOnLevel.push(value);19}20
21// Формируем данные по каждому узлу22for (let i = 0; i < nodes.length; i++) {23let template = ""; // Шаблон для узла, имеющего дочерние элементы24const node = nodes[i]; // Текущий узел25const nodesOnThisLevel = nodes.filter((item) => item.level === node.level); // Все узлы на данном уровне вложенности26const valueLengthsSum = maxValuesLengthOnLevel27.slice(0, node.level)28.reduce((a, b) => a + b, 0); // Сумма максимальных длин символов ДО текущего уровня вложенности (используется для создания отступов)29
30// Если у узла есть дочерние элементы, добавляем в шаблон строку (n*"-")---+31if (nodes[i + 1] && node.level < nodes[i + 1].level) {32const lastLength = maxValuesLengthOnLevel[node.level];33template = "-".repeat(lastLength - node.value.length) + "---+";34}35
36// Создаем значение строки по текущему узлу (отступы + значение + шаблон)37let treeValue =38" ".repeat(node.level * 3 + valueLengthsSum) + node.value + template;39
40// Добавляем в строку вертикальные линии41for (const position of verticalLinePositions) {42treeValue =43treeValue.slice(0, position) + "|" + treeValue.slice(position + 1);44}45
46// Если на данном уровне есть еще элементы и уровень вложенности следующего элемента больше47if (48nodesOnThisLevel.length !== 1 &&49nodes[i + 1] &&50node.index !== nodesOnThisLevel.at(-1).index &&51node.level < nodes[i + 1].level52) {53// Находим индекс следующего узла на данном уровне54const nextNodeIndex =55nodesOnThisLevel.findIndex((item) => item.index === node.index) + 1;56// Берем массив узлов от текущего индекса до индекса следующего узла на данном уровне57const nodesBetweenIndex = nodes.slice(58node.index,59nodesOnThisLevel[nextNodeIndex].index60);61
62let validLevels = true; // Валидность уровней узлов63
64// Если хотя бы один узел имеет уровень вложенности меньше текущего, то валидность уровне устанавливается в false65for (const nodeBI of nodesBetweenIndex) {66if (nodeBI.level < node.level) validLevels = false;67}68
69// Если валидность уровней узлов true, то добавляем новую позицию для | в массив verticalLinePositions70if (validLevels) {71verticalLinePositions.push(node.level * 3 + valueLengthsSum);72}73}74
75// Если уровень вложенности будет уменьшаться, убираем последнюю позицию для вертикальной линии76if (nodes[i + 1] && node.level > nodes[i + 1].level) {77verticalLinePositions.pop();78}79
80// Добавляем конечную строку к дереву81tree += `<pre>${treeValue}</pre>`;82}83
84return tree;85}
86