@@ -14,29 +14,27 @@ class TreeLayoutEngine {
1414 this . blocks = new Map ( blocks . map ( ( block : any ) => [ block . id , { ...block } ] ) ) ;
1515 this . connections = connections ;
1616
17- // Настройки отступов
17+ // Layout settings
1818 this . options = {
19- horizontalSpacing : options . horizontalSpacing || 40 , // расстояние между блоками по горизонтали
20- verticalSpacing : options . verticalSpacing || 20 , // расстояние между уровнями
19+ horizontalSpacing : options . horizontalSpacing || 40 , // horizontal distance between blocks
20+ verticalSpacing : options . verticalSpacing || 20 , // vertical distance between levels
2121 ...options ,
2222 } ;
2323
2424 this . tree = null ;
2525 this . levels = [ ] ;
2626 }
2727
28- // Построение структуры дерева
28+ // Building a tree structure
2929 buildTree ( ) {
30- // Создаем карты родителей и детей
3130 const childrenMap = new Map ( ) ;
3231 const parentMap = new Map ( ) ;
3332
34- // Инициализируем карты
3533 for ( const block of this . blocks . values ( ) ) {
3634 childrenMap . set ( block . id , [ ] ) ;
3735 }
3836
39- // Заполняем связи
37+ // Setting connections
4038 for ( const connection of this . connections ) {
4139 const parent = connection . sourceBlockId ;
4240 const child = connection . targetBlockId ;
@@ -45,14 +43,14 @@ class TreeLayoutEngine {
4543 parentMap . set ( child , parent ) ;
4644 }
4745
48- // Находим корневой узел (узел без родителя )
46+ // Find root (a node without a parent )
4947 const rootId = Array . from ( this . blocks . keys ( ) ) . find ( ( id ) => ! parentMap . has ( id ) ) ;
5048
5149 if ( ! rootId ) {
5250 throw new Error ( 'Root node not found' ) ;
5351 }
5452
55- // Рекурсивно строим дерево
53+ // Recursively building a tree
5654 const buildNode = ( nodeId : string , level = 0 ) : TreeNode => {
5755 const block = this . blocks . get ( nodeId ) ;
5856 const children = childrenMap
@@ -74,7 +72,7 @@ class TreeLayoutEngine {
7472 return this . tree ;
7573 }
7674
77- // Группировка узлов по уровням
75+ // Grouping nodes by levels
7876 groupByLevels ( node : TreeNode | null = this . tree , levels : TreeNode [ ] [ ] = [ ] ) : TreeNode [ ] [ ] {
7977 if ( ! node ) {
8078 return levels ;
@@ -93,65 +91,65 @@ class TreeLayoutEngine {
9391 return levels ;
9492 }
9593
96- // Вычисление ширины поддерева для каждого узла
94+ // Calculating the width of the subtree for each node
9795 calculateSubtreeWidths ( node : TreeNode = this . tree ! ) : number {
9896 if ( node . children . length === 0 ) {
99- // Листовой узел - ширина равна ширине блока
97+ // Leaf node - width is equal to the width of the block
10098 node . subtreeWidth = node . block . width ;
10199 } else {
102- // Рекурсивно вычисляем ширину для детей
100+ // Recursively calculating the width for children
103101 for ( const child of node . children ) {
104102 this . calculateSubtreeWidths ( child ) ;
105103 }
106104
107- // Ширина поддерева = сумма ширин поддеревьев детей + отступы между ними
105+ // Subtree width = sum of the widths of the children's subtrees + the margins between them
108106 const childrenWidth = node . children . reduce (
109107 ( sum : number , child : TreeNode ) => sum + child . subtreeWidth ,
110108 0 ,
111109 ) ;
112110 const spacingWidth = ( node . children . length - 1 ) * this . options . horizontalSpacing ;
113111 const totalChildrenWidth = childrenWidth + spacingWidth ;
114112
115- // Ширина поддерева = максимум из ширины самого узла и суммарной ширины детей
113+ // Subtree width = the maximum of the width of the node itself and the total width of the children
116114 node . subtreeWidth = Math . max ( node . block . width , totalChildrenWidth ) ;
117115 }
118116
119117 return node . subtreeWidth ;
120118 }
121119
122- // Размещение узлов по позициям
120+ // Placement of nodes by position
123121 positionNodes ( ) {
124122 if ( ! this . tree ) {
125123 return ;
126124 }
127125
128- // Вычисляем Y координаты для каждого уровня
126+ // Calculating the Y coordinates for each level
129127 let currentY = 0 ;
130128 const levelY : number [ ] = [ ] ;
131129
132130 for ( let level = 0 ; level < this . levels . length ; level ++ ) {
133131 levelY [ level ] = currentY ;
134132
135- // Находим максимальную высоту блоков на этом уровне
133+ // We find the maximum height of the blocks at this level
136134 const maxHeight = Math . max (
137135 ...this . levels [ level ] . map ( ( node : TreeNode ) => node . block . height ) ,
138136 ) ;
139137 currentY += maxHeight + this . options . verticalSpacing ;
140138 }
141139
142- // Рекурсивно размещаем узлы
140+ // Recursively placing nodes
143141 const positionNode = ( node : TreeNode , leftX : number ) : void => {
144- // Устанавливаем Y координату
142+ // Setting the Y coordinate
145143 node . y = levelY [ node . level ] ;
146144
147145 if ( node . children . length === 0 ) {
148- // Листовой узел - размещаем в текущей позиции
146+ // The leaf node is placed in the current position.
149147 node . x = leftX ;
150148 } else {
151- // Размещаем детей
149+ // Place children
152150 let childX = leftX ;
153151
154- // Если ширина узла больше суммарной ширины детей, добавляем отступ
152+ // If the node width is greater than the total width of the children, add an indentation.
155153 const childrenWidth = node . children . reduce (
156154 ( sum : number , child : TreeNode ) => sum + child . subtreeWidth ,
157155 0 ,
@@ -164,13 +162,13 @@ class TreeLayoutEngine {
164162 childX += extraSpace ;
165163 }
166164
167- // Размещаем каждого ребенка
165+ // Place each child
168166 for ( const child of node . children ) {
169167 positionNode ( child , childX ) ;
170168 childX += child . subtreeWidth + this . options . horizontalSpacing ;
171169 }
172170
173- // Центрируем родительский узел относительно детей
171+ // Center the parent node relative to the children
174172 const firstChild = node . children [ 0 ] ;
175173 const lastChild = node . children [ node . children . length - 1 ] ;
176174 const childrenCenter = ( firstChild . x + lastChild . x + lastChild . block . width ) / 2 ;
@@ -181,7 +179,7 @@ class TreeLayoutEngine {
181179 positionNode ( this . tree , 0 ) ;
182180 }
183181
184- // Нормализация координат (чтобы минимальные координаты были >= 0)
182+ // Normalization of coordinates (so that the minimum coordinates are >= 0)
185183 normalizeCoordinates ( ) {
186184 if ( ! this . tree ) {
187185 return ;
@@ -201,7 +199,7 @@ class TreeLayoutEngine {
201199 const minX = Math . min ( ...allNodes . map ( ( node ) => node . x ) ) ;
202200 const minY = Math . min ( ...allNodes . map ( ( node ) => node . y ) ) ;
203201
204- // Сдвигаем все координаты так, чтобы минимальные были равны 0
202+ // Shift all coordinates so that the minimum ones are equal to 0
205203 const offsetX = minX < 0 ? - minX : 0 ;
206204 const offsetY = minY < 0 ? - minY : 0 ;
207205
@@ -211,7 +209,7 @@ class TreeLayoutEngine {
211209 }
212210 }
213211
214- // Основной метод компоновки
212+ // Main method of composition
215213 layout ( ) {
216214 this . buildTree ( ) ;
217215 this . groupByLevels ( ) ;
@@ -222,7 +220,7 @@ class TreeLayoutEngine {
222220 return this . getLayoutResult ( ) ;
223221 }
224222
225- // Получение результата компоновки
223+ // Getting the result of composition
226224 getLayoutResult ( ) : ExtendedTBlock [ ] {
227225 if ( ! this . tree ) {
228226 return [ ] ;
@@ -252,17 +250,17 @@ class TreeLayoutEngine {
252250 }
253251}
254252
255- // Функция для использования алгоритма
253+ // Function for using the algorithm
256254function calculateTreeLayout ( blocks : TBlock [ ] , connections : TConnection [ ] , options = { } ) {
257255 const engine = new TreeLayoutEngine ( blocks , connections , options ) ;
258256 return engine . layout ( ) ;
259257}
260258
261259function calculateTreeEdges ( layoutResult : ExtendedTBlock [ ] , connections : TConnection [ ] ) {
262- // Создаем карту позиций для удобства поиска
260+ // Create a position map for convenience of search
263261 const positionMap = new Map ( layoutResult . map ( ( item ) => [ item . id , item ] ) ) ;
264262
265- // Группируем связи по родительскому блоку
263+ // Group connections by parent block
266264 const connectionsByParent = new Map ( ) ;
267265
268266 for ( const connection of connections ) {
@@ -280,19 +278,19 @@ function calculateTreeEdges(layoutResult: ExtendedTBlock[], connections: TConnec
280278 points : { x : number ; y : number } [ ] ;
281279 } [ ] = [ ] ;
282280
283- // Для каждого родительского блока рассчитываем пути к детям
281+ // For each parent block, we calculate the paths to the children
284282 for ( const [ parentId , parentConnections ] of connectionsByParent ) {
285283 const parent = positionMap . get ( parentId ) ;
286284 if ( ! parent ) {
287285 continue ;
288286 }
289287
290- // Координаты начальной точки (центр нижней части родителя )
288+ // Coordinates of the initial point (center of the lower part of the parent )
291289 const startX = parent . x + parent . width / 2 ;
292290 const startY = parent . y + parent . height ;
293291
294292 if ( parentConnections . length === 1 ) {
295- // Один дочерний блок - простая прямая линия
293+ // One child block - simple straight line
296294 const connection = parentConnections [ 0 ] ;
297295 const child = positionMap . get ( connection . targetBlockId ) ;
298296
@@ -311,9 +309,9 @@ function calculateTreeEdges(layoutResult: ExtendedTBlock[], connections: TConnec
311309 } ) ;
312310 }
313311 } else {
314- // Несколько дочерних блоков - ломаные линии
312+ // Several child blocks - broken lines
315313
316- // Находим вертикальное расстояние между родителем и ближайшим ребенком
314+ // We find the vertical distance between the parent and the nearest child
317315 const children = parentConnections
318316 . map ( ( conn : TConnection ) => positionMap . get ( conn . targetBlockId ) )
319317 . filter (
@@ -325,13 +323,13 @@ function calculateTreeEdges(layoutResult: ExtendedTBlock[], connections: TConnec
325323 continue ;
326324 }
327325
328- // Находим минимальное расстояние до детей по Y
326+ // We find the minimum distance to the children by Y
329327 const minChildY = Math . min ( ...children . map ( ( child : ExtendedTBlock ) => child . y ) ) ;
330328
331- // Точка разветвления - посередине между родителем и детьми
329+ // The point of branching - in the middle between the parent and the children
332330 const branchY = startY + ( minChildY - startY ) / 2 ;
333331
334- // Для каждого дочернего блока создаем ломаную линию
332+ // For each child block, we create a broken line
335333 for ( const connection of parentConnections ) {
336334 const child = positionMap . get ( connection . targetBlockId ) ;
337335 if ( ! child ) {
@@ -342,10 +340,10 @@ function calculateTreeEdges(layoutResult: ExtendedTBlock[], connections: TConnec
342340 const endY = child . y ;
343341
344342 const points = [
345- { x : startX , y : startY } , // Начало - центр нижней части родителя
346- { x : startX , y : branchY } , // Вертикально вниз до точки разветвления
347- { x : endX , y : branchY } , // Горизонтально до центра дочернего блока
348- { x : endX , y : endY } , // Вертикально вниз до центра верхней части дочернего блока
343+ { x : startX , y : startY } , // Start - center of the lower part of the parent
344+ { x : startX , y : branchY } , // Vertically down to the point of branching
345+ { x : endX , y : branchY } , // Horizontally to the center of the child block
346+ { x : endX , y : endY } , // Vertically down to the center of the upper part of the child block
349347 ] ;
350348
351349 connectionPaths . push ( {
0 commit comments