Javascript-форум (https://javascript.ru/forum/)
-   Javascript под браузер (https://javascript.ru/forum/css-html/)
-   -   Обмен узлов между двумя деревьями (https://javascript.ru/forum/css-html/81840-obmen-uzlov-mezhdu-dvumya-derevyami.html)

jabbascript 04.02.2021 17:33

Обмен узлов между двумя деревьями
 
Здравствуйте!!!
Хочу разобраться как можно осуществить смену узлов 2х деревьев с n вложенностью(узел получаем по клику, по факту это будет драг энд дроп). Корневой узел перетаскивает всех дочерних, любой дочерний может стать корневым и дочерним для любого другого узла в своем дереве или соседнем. Учитывается позиция.

1. Какие нужно учесть условия чтобы это стало возможо?
2. Задачка конечно ппц, хочется както понять с чего начать)

Допустим есть входящие данные такие:
const tree1 = [
	{
		id: 1, 
		title: 'node1', 
		children: [
			{
				id: 3, 
				title: 'sub node1' ,
			}, 
			{ 
				id: 4, 
				title: 'sub node1' , 
				children: [ { id: 5, title: 'sub sub node1'}]
			}
		] ,
	},
	{
		id: 2, 
		title: 'node2', 
		children: [
			{
				id: 6, 
				title: 'sub node2' ,
			}, 
			{ 
				id: 7, title: 'sub node2' , 
				children: [ { id: 8, title: 'sub sub node2'}]
			}
		] ,
	}
];

const tree2 = [
	{
		id: 9, 
		title: 'node1', 
		children: [
			{
				id: 10, 
				title: 'sub node1' ,
			}, 
			{ 
				id: 11, title: 'sub node1' , 
				children: []
			}
		] ,
	},
	{
		id: 12, 
		title: 'node2', 
		children: [
			{
				id: 13, 
				title: 'sub node2' ,
			}, 
			{ 
				id: 14, 
				title: 'sub node2' , 
				children: [ { id: 15, title: 'sub sub node2'}]
			}
		] ,
	}
];

const treeToTreeNodes = (tree1, tree2) => {

}

voraa 04.02.2021 18:16

По моему у ваших деревьев не хватает полноценного корня.
Должно быть как то так
const tree1 = {
id: 0,
title: 'root',
children: [
		{
			id: 1,
			title: 'node1',
			children: [
				{
					id: 3,
					title: 'sub node1' ,
				},
				{
					id: 4,
					title: 'sub node1' ,
					children: [ { id: 5, title: 'sub sub node1'}]
				}
			] ,
		},
		{
			id: 2,
			title: 'node2',
			children: [
				{
					id: 6,
					title: 'sub node2' ,
				},
				{
					id: 7, title: 'sub node2' ,
					children: [ { id: 8, title: 'sub sub node2'}]
				}
			] ,
		}
	]
};


const treeToTreeNodes = (tree1, tree2) => {}

И какая конкретно операция должна быть выполнена? Что вставить и куда?

jabbascript 05.02.2021 08:54

Допустим я беру и удаляю ноду из tree2:
{
		id: 12, 
		title: 'node2', 
		children: [
			{
				id: 13, 
				title: 'sub node2' ,
			}, 
			{ 
				id: 14, 
				title: 'sub node2' , 
				children: [ { id: 15, title: 'sub sub node2'}]
			}
		] ,
	}

и ее вставляю в tree1 между:
{
				id: 6, 
				title: 'sub node2' ,
			},

и
{ 
				id: 7, title: 'sub node2' , 
				children: [ { id: 8, title: 'sub sub node2'}]
			}

и так далее все возможные комбинации.

voraa 05.02.2021 11:05

Если такие операции требуются часто, я бы сделал класс, хотя бы с минимально необходимыми функциями работы с деревом.
Ну как то так
class Node {
// Создает узел дерева.
// fields - объект с полями определяемыми пользователем
// childs - массив дочерних узлов (необязат)
	constructor (fields, childs) {
		this.parent = null;
		this.childs = [];
		for (const f in fields) {
			this[f] = fields[f];
		}
		if (childs) {
			for (const ch of childs) {
				this.append(ch);
			}
		}
	}

// Добавить узел nd, как последний дочерний к текущему	
	append (nd) {
		nd.remove();
		nd.parent = this;
		this.childs.push(nd)
		return this
	}
	
// Найти в текущем и среди всех его потомков узел, удовлетворяющий условию,
// задаваемому функцией  fcmp	
	find (fcmp) {
		if (fcmp(this)) return this;
		for (const ch of this.childs) {
			const rf = ch.find (fcmp)
			if (rf) return rf;
		}
		return null;
	}
	
// Удалить узел
// nd.remove () удаляет узел  nd из его родителя.
// par.remove (nd) удаляет из дочерних par узел nd
	remove (nd) {
		let par = this;
		if (nd === undefined) {
			par = this.parent;
			nd = this;
		}
		if (!par || !nd) return
		const ind = par.childs.indexOf(nd);
		if (ind < 0) return;
		par.childs.splice(ind, 1);
		nd.parent = null;
		return nd;
	}
	
// Вставляет узел nd перед текущим, в его родительский узел, если он есть
	before (nd) {
		const par = this.parent;
		if (!par) return;
		nd.remove();
		const ind = par.childs.indexOf(nd);
		par.childs.splice(ind, 0, nd)
		nd.parent = this;
		return this;
	}
	
	toString () {
		let s = '{'
		for (const f in this) {
			if (f == 'childs') continue;
			if (f == 'parent') continue;
			s += `${f}: ${this[f].toString()}, `
		}
		s+='childs: ['
		for (const ch of this.childs) {
			s+=ch.toString() + ','
		}
		s+=']}'
		return s
	}
}

const tree1 = new Node ({},
	[
		new Node ({id: 1, title: 'node1'},
			[
				new Node ({id: 3, title: 'sub node1'}),
				new Node ({id: 4, title: 'sub node1'}, [new Node ({ id: 5, title: 'sub sub node1'})]),
			]),
		new Node ({id: 2, title: 'node2'}, 
			[
				new Node ({id: 6, title: 'sub node2'}),
				new Node ({id: 7, title: 'sub node2'}, [new Node ({ id: 8, title: 'sub sub node2'})]),
			])
		
	]);
	
const tree2 = new Node ({},
	[
		new Node ({id: 9, title: 'node1'},
			[
				new Node ({id: 10, title: 'sub node1'}),
				new Node ({id: 11, title: 'sub node1'}),
			]),
		new Node ({id: 12, title: 'node2'}, 
			[
				new Node ({id: 13, title: 'sub node2'}),
				new Node ({id: 14, title: 'sub node2'}, [new Node ({ id: 15, title: 'sub sub node2'})]),
			])
		
	]);
	
console.log(tree1.toString());
console.log(tree2.toString());
// Допустим я беру и удаляю ноду из tree2:
// и ее вставляю в tree1 между:
const nd12 = tree2.find (nd => nd.id == 12)
const nd7 = tree1.find (nd => nd.id == 7)
nd7.before(nd12)

console.log(tree1.toString());
console.log(tree2.toString());

Vlasenko Fedor 05.02.2021 13:07

https://www.jstree.com/demo/
https://dbushell.github.io/Nestable/
и много других
тут вопрос целесообразности своего велосипеда :cray: или изспользованя готовых либ :dance:
как не крути если хочешь свое, то нужно смотреть, что есть хорошее у других
пример с учебника и здесь на сайте где то в учебнике было примитивное дерево
https://learn.javascript.ru/drag-and-drop-plus

jabbascript 05.02.2021 14:29

Цитата:

Сообщение от Vlasenko Fedor (Сообщение 533489)
https://www.jstree.com/demo/
https://dbushell.github.io/Nestable/
и много других
тут вопрос целесообразности своего велосипеда :cray: или изспользованя готовых либ :dance:
как не крути если хочешь свое, то нужно смотреть, что есть хорошее у других
пример с учебника и здесь на сайте где то в учебнике было примитивное дерево
https://learn.javascript.ru/drag-and-drop-plus

https://dbushell.github.io/Nestable/ Это круто и я бы взял, но мне такое надо на React)

voraa 05.02.2021 14:30

Цитата:

Сообщение от Vlasenko Fedor
тут вопрос целесообразности своего велосипеда или изспользованя готовых либ

Эти готовые либы работают с DOM.
А оно надо?
Зачем в простом случае тащить готовую либу, где 90% не требуется?
Цитата:

Сообщение от Vlasenko Fedor
https://learn.javascript.ru/drag-and-drop-plus

Где дерево то?

jabbascript 05.02.2021 14:37

Проблема сейчас в том что мне нужно подобие этого https://frontend-collective.github.i...-tree-dragging, но то что есть у них не работает, выдает ошибку.

Vlasenko Fedor 05.02.2021 18:13

Цитата:

Сообщение от voraa
Зачем в простом случае тащить готовую либу, где 90% не требуется?

чтоб не тратить время на свой велосипед, взять готовое,чтоб не тестить и не ловить баги во всех браузерах, потратить время на другое
в нынешнее время плевать на 10k на вебе можно
в конце ТС ответил про react :lol:
avesome react tree
https://reactscript.com/best-tree-view/
с React не подскажу, у меня к нему особое мнение :)


Часовой пояс GMT +3, время: 20:11.