Тема: Побудова з'єднувальних ліній для деревоподібної структури
Вітаю.
Нещодавно в мене виникло завдання - для дерева з елементів домалювати лінії, котрі б допомогали орієнтуватися, який елемент є дочірнім до якого.
Виглядати воно мало б ось так
В оригіналі, всі елементи, що мають дочірні елементи можна згортати і розгортати, тому для випадку, коли ми по-черзі розгортаємо кожен елемент я написав такий от код:
При розгортанні елемента А, ми беремо кількість його безпосередніх дочірніх елементів (це ті, котрі є саме дітьми того елемента, а не дітьми дітей), та додаємо це число до певної змінної всіх наступних елементів, рівень вкладенності (або глибина, або відступ зліва) котрих дорівнює, або менший за рівень вкладеності елемента А, при цьому у нас немає можливості зачіпати елементи з меншим або рівним рівнем, ніж рівень минулого елемента.
Тобто, на цій картинці, якщо ми розгортаємо виділений товстою рамкою елемент, то ми отримуємо кількість його безпосередніх дітей, а це 2, і проходимось по вім наступним елементам, при цьому зберігаючи рівень вкладеності кожного елемента, і якщо рівень вкладеності наступного елемента менший, або такий самий, як збережений, то ми того елемента ігноруємо, а до деякої змінної решти елементів додаємо 2.
Таким чином елементи "Tree element 5" та "Tree element 9" додадуть до своєї змінної 2. І це правильно, адже ці елементи опустяться на 2 висоти нижче, і їхні лінії мають бути на 2 висоти вищими.
Справжнє питання починається тут
А потім мені необхідно було зробити функцію, котра відкриває всі елементи, що мають дітей, і при цьому теж необхідно порахувати висоту лінії для кожного елемента.
Відкривати всі елементи я вирішив рекурсією.
Зробив я це так
1. Проходимось по масиву елементів з 1 рівнем (в цей момент всі елементи з дітьми є згорнутими)
1.1 Додаємо елемент в масив всіх елементів
1.2 Перевіряємо, чи в цього мелемента є діти:
так: проходимось по всім дітям елемента --> 1.1
ні: повертаємось з функції
після виконання цієї функції у нас є масив, що містить в собі всі елементи дерева.
Після цього потрібно було б обрахувати змінні, що являють собою множник для константи, котра є висотою одного елемента. Але я подумав, що ці змінні 100% можна обрахувати в тій рекурсивній функції.
І от я кулупався в ній, але ця рекурсія постійно викликала в моєму мозку stack overflow exception, і я так і не зміг в межах одного дня написати правильний код.
Сьогодні я то зміг зробити, але я не 100% впевнений, чи він буде працювати з усіма можливими деревами, а писати функцію, котра б будувала рандомні дерева, мені ліньки.
Ось заготовка під все це https://jsfiddle.net/jvxpefkL/52/
Все починається в функціїї "expandAll", в ній ми починаємо перебирати елементи першого рівня та передавати їх в функцію "addRecursively", котра додасть самі елементи та всіх їх дітей, та онуків, та правнуків до масиву. Також в функції "addRecursively" треба розрахувати довжину лінії для кожного елементу. Для цього треба встановити правильне значення в змінну "lineHeightMultiplier".
1 - це висота одного елементу. На цій картинці показано, яке значення "lineHeightMultiplier" повинен мати кожен елемент. При цьому елементи першого рівня можна ігнорувати.
Кому не ліньки, я вас прошу спробувати модифікувати функцію "addRecursively" таким чином, аби кожен елемент мав правильне значення "lineHeightMultiplier", і сказати, як складно вам то було. Якщо не вдалося розібратись, то теж кажіть.