1

Тема: Побудова з'єднувальних ліній для деревоподібної структури

Вітаю.
Нещодавно в мене виникло завдання - для дерева з елементів домалювати лінії, котрі б допомогали орієнтуватися, який елемент є дочірнім до якого.
Виглядати воно мало б ось так

Прихований текст

(не звертайте уваги на виділений жовтим проміжок, то через всі ті margin'и та border'и)
https://cdn.discordapp.com/attachments/333936584481177600/508640240580427777/unknown.png

В оригіналі, всі елементи, що мають дочірні елементи можна згортати і розгортати, тому для випадку, коли ми по-черзі розгортаємо кожен елемент я написав такий от код:

При розгортанні елемента А, ми беремо кількість його безпосередніх дочірніх елементів (це ті, котрі є саме дітьми того елемента, а не дітьми дітей), та додаємо це число до певної змінної всіх наступних елементів, рівень вкладенності (або глибина, або відступ зліва) котрих дорівнює, або менший за рівень вкладеності елемента А, при цьому у нас немає можливості зачіпати елементи з меншим або рівним рівнем, ніж рівень минулого елемента.

Тобто, на цій картинці, якщо ми розгортаємо виділений товстою рамкою елемент, то ми отримуємо кількість його безпосередніх дітей, а це 2, і проходимось по вім наступним елементам, при цьому зберігаючи рівень вкладеності кожного елемента, і якщо рівень вкладеності наступного елемента менший, або такий самий, як збережений, то ми того елемента ігноруємо, а до деякої змінної решти елементів додаємо 2.
Таким чином елементи "Tree element 5" та "Tree element 9" додадуть до своєї змінної 2. І це правильно, адже ці елементи опустяться на 2 висоти нижче, і їхні лінії мають бути на 2 висоти вищими.

Прихований текст

https://cdn.discordapp.com/attachments/333936584481177600/508655281077616642/unknown.png

Справжнє питання починається тут
А потім мені необхідно було зробити функцію, котра відкриває всі елементи, що мають дітей, і при цьому теж необхідно порахувати висоту лінії для кожного елемента.

Відкривати всі елементи я вирішив рекурсією.
Зробив я це так

1. Проходимось по масиву елементів з 1 рівнем (в цей момент всі елементи з дітьми є згорнутими)
  1.1 Додаємо елемент в масив всіх елементів
  1.2 Перевіряємо, чи в цього мелемента є діти:
          так: проходимось по всім дітям елемента --> 1.1
          ні:   повертаємось з функції

після виконання цієї функції у нас є масив, що містить в собі всі елементи дерева.

Після цього потрібно було б обрахувати змінні, що являють собою множник для константи, котра є висотою одного елемента. Але я подумав, що ці змінні 100% можна обрахувати в тій рекурсивній функції.
І от я кулупався в ній, але ця рекурсія постійно викликала в моєму мозку stack overflow exception, і я так і не зміг в межах одного дня написати правильний код.

Сьогодні я то зміг зробити, але я не 100% впевнений, чи він буде працювати з усіма можливими деревами, а писати функцію, котра б будувала рандомні дерева, мені ліньки.

Ось заготовка під все це https://jsfiddle.net/jvxpefkL/52/
Все починається в функціїї "expandAll", в ній ми починаємо перебирати елементи першого рівня та передавати їх в функцію "addRecursively", котра додасть самі елементи та всіх їх дітей, та онуків, та правнуків до масиву. Також в функції "addRecursively" треба розрахувати довжину лінії для кожного елементу. Для цього треба встановити правильне значення в змінну "lineHeightMultiplier".
1 - це висота одного елементу. На цій картинці показано, яке значення "lineHeightMultiplier" повинен мати кожен елемент. При цьому елементи першого рівня можна ігнорувати.

Прихований текст

https://cdn.discordapp.com/attachments/333936584481177600/508660304121430017/unknown.png

Кому не ліньки, я вас прошу спробувати модифікувати функцію "addRecursively" таким чином, аби кожен елемент мав правильне значення "lineHeightMultiplier", і сказати, як складно вам то було. Якщо не вдалося розібратись, то теж кажіть.

Подякували: leofun011

2 Востаннє редагувалося leofun01 (05.11.2018 02:24:56)

Re: Побудова з'єднувальних ліній для деревоподібної структури

FakiNyan написав:

модифікувати функцію "addRecursively" таким чином, аби кожен елемент мав правильне значення "lineHeightMultiplier"

Я зробив не те, що ви просили, але вам сподобається.
Все необхідне в архіві.

FakiNyan написав:

, і сказати, як складно вам то було.

Було не легко, але чого не зробиш заради кастомізабельності.

Post's attachments

html_css_tree.7z 1.42 kb, 301 downloads since 2018-11-05 

Подякували: FakiNyan1

3 Востаннє редагувалося leofun01 (05.11.2018 02:27:15)

Re: Побудова з'єднувальних ліній для деревоподібної структури

Результати має бути отаким
https://replace.org.ua/misc.php?action=pun_attachment&item=1939&download=0

Post's attachments

html_tree_chrome_320px.png 10.53 kb, 96 downloads since 2018-11-05 

Подякували: FakiNyan1

4

Re: Побудова з'єднувальних ліній для деревоподібної структури

Цікавий варіянт. Але для моєї задачі таке не підійшло б, тому що все дерево знаходиться всередині віртуального скролу, і щоб той скрол правильно рахував кількість елементів, необхідно, аби всі вони були безпосередніми дітьми скролу.

5

Re: Побудова з'єднувальних ліній для деревоподібної структури

FakiNyan написав:

все дерево знаходиться всередині віртуального скролу, і щоб той скрол правильно рахував кількість елементів, необхідно, аби всі вони були безпосередніми дітьми скролу.

? ем... "безпосередніми дітьми" ... щось мені підказує, що це не найкраще рішення...

6

Re: Побудова з'єднувальних ліній для деревоподібної структури

leofun01 написав:
FakiNyan написав:

все дерево знаходиться всередині віртуального скролу, і щоб той скрол правильно рахував кількість елементів, необхідно, аби всі вони були безпосередніми дітьми скролу.

? ем... "безпосередніми дітьми" ... щось мені підказує, що це не найкраще рішення...

чому?

Подякували: leofun011

7 Востаннє редагувалося leofun01 (07.11.2018 02:08:17)

Re: Побудова з'єднувальних ліній для деревоподібної структури

FakiNyan написав:
leofun01 написав:

... це не найкраще рішення...

чому?

Ви створюєте дерево елементів (як мінімум візуально) і створюєте теги в HTML. Очевидно, що ваше "візуальне дерево" і дерево тегів мають бути ізоморфні.
Тобто елемент (A1), який виглядає як дочірній елемент іншого елемента (А), маює бути реально дочірнім елементом для A, а не для якогось "контейнера-всеотця".

8

Re: Побудова з'єднувальних ліній для деревоподібної структури

ви що, консерватор-традиціоналіст?