Javascript-форум (https://javascript.ru/forum/)
-   Общие вопросы Javascript (https://javascript.ru/forum/misc/)
-   -   Бинарное древо (отрисовка), объекты (https://javascript.ru/forum/misc/70935-binarnoe-drevo-otrisovka-obekty.html)

d1ver 13.10.2017 10:19

Бинарное древо (отрисовка), объекты
 
Всем здравствуйте.
Есть некоторый код:

<script type="text/javascript">
function drawPoly (id, arr) { //id тега <canvas> и массив координат
	var canvas = document.getElementById(id).getContext('2d');
	// Отрисовка
	canvas.clearRect(0,0,500,400);
	canvas.beginPath();
	clear_all();

	for (var i = 0; i < arr.length; i++) {
*!*
		canvas.strokeRect(arr[`${i}`].x + 250, arr[`${i}`].y * 10, 5, 5);

		console.log("x: " + arr[`${i}`].x + " y: " + arr[`${i}`].y);
*/!*
	}
}

function clear_all (){
	console.clear();
}

function BinarySearchTree() {
    this.root = null;
    this.index = 0;
}

BinarySearchTree.prototype.add = function(value) {
    var currentNode = this.makeNode(value);
    if (!this.root) {
        this.root = currentNode;
    } else {
        this.insert(currentNode);
    }
    return this;
};

BinarySearchTree.prototype.makeNode = function(value) {
    var node = {};
    node.value = value;
    node.info = {};
    node.left = null;
    node.right = null;
	node.parent = null;
	node.depth = 0;
	node.drawPoint = {
		x: 0,
		y: 0
	}
	node.index = this.index;
	this.index += 1;
    return node;
};

BinarySearchTree.prototype.insert = function(currentNode) {
    var value = currentNode.value;

    var traverse = function(node) {
        //if value is equal to the value of the node, ignore
        //and exit function since we don't want duplicates
        if (value === node.value) {
            return;
        } else if (value > node.value) {
            if (!node.right) {
                node.right = currentNode;
				node.depth++;
                return;
            } else
                traverse(node.right);
        } else if (value < node.value) {
            if (!node.left) {
                node.left = currentNode;
				node.depth++;
                return;
            } else
                traverse(node.left);
        }
    };
    traverse(this.root);
};


BinarySearchTree.prototype.setDepth = function() {
    var node = this.root;
    var maxDepth = 0;
    var traverse = function(node, depth) {
        if (!node) return null;
        if (node) {
            maxDepth = depth > maxDepth ? depth : maxDepth;
			node.depth = depth;
			//set parent too
			if (node.right){
				(node.right).parent = node;
			}
			if (node.left){
        		(node.left).parent = node;
        	}
            traverse(node.left, depth + 1);
            traverse(node.right, depth + 1);
        }
    };
    traverse(node, 1);
};

BinarySearchTree.prototype.maxDepth = function() {
    var node = this.root;
    var maxDepth = 0;
    var traverse = function(node) {
        if (!node) return null;
        if (node) {
            maxDepth = node.depth > maxDepth ? node.depth : maxDepth;
            traverse(node.left);
            traverse(node.right);
        }
    };
    traverse(node, 0);
    return maxDepth;
};

BinarySearchTree.prototype.setDrawPoint = function(maxDepth, resizer) {
    var node = this.root;
    var parentX, coef;
    var traverse = function(node, left) {
        if (!node) return null;
        if (node) {
*!*
        	parentX = node.parent ? (node.parent).drawPoint.x : 0;
        	parentX = left ? - parentX : parentX;
        	coef = left ? -coef : coef;
			node.drawPoint.x = parentX + Math.pow(2, maxDepth - node.depth);
			node.drawPoint.y = node.depth + resizer;
*/!*
            traverse(node.left, true);
            traverse(node.right);
        }
    };
    traverse(node);
};

BinarySearchTree.prototype.checkDrawPoint = function() {
    var node = this.root;
    var drawPoint = {};
    var counter = 0;
    var traverse = function(node) {
        if (!node) return null;
        if (node) {
        	*!*drawPoint[`${node.index}`] = node.drawPoint;*/!*
        	counter++;
            traverse(node.left);
            traverse(node.right);
        }
    };
    traverse(node, 0);
    drawPoint.length = counter;
    return drawPoint;
};


BinarySearchTree.prototype.setInfo = function() {
    var node = this.root;
    var traverse = function(node) {
        if (!node) return null;
        if (node) {
		    node.info = {};
			node.info.depth = node.depth;
			node.info.index = node.index;
			node.info.parent = node.parent;
			delete node.parent;
			delete node.depth;
			delete node.index;
            traverse(node.left);
            traverse(node.right);
        }
    };
    traverse(node, 0);
};

function BinaryTreeConstructor (num) {
	var tree = new BinarySearchTree();
	for (let i = 0; i < num; i++) {
		tree.add(parseInt((Math.random()*1000).toFixed(1)));
	}
	tree.setDepth();
	*!*tree.setDrawPoint(tree.maxDepth(), 0);*/!*
        delete(tree.index);
	return tree;
}

function createCoordArray(num) {
	var tree = new BinaryTreeConstructor(num);
	*!*var coordArray = tree.checkDrawPoint();*/!*
	return coordArray;
}





</script>
 
<form>
<canvas style='border:1px dashed #888;' id='canvasId' width='500' height='400'>
Извините, тег Canvas недоступен!
</canvas>
<br>
<input style="width:auto;" type="button" value="Draw" onclick="drawPoly('canvasId', createCoordArray(document.getElementById('count').value))">
<input style="width:auto;" type="text" value="10" id="count">
</form>



Суть проблемы: при работе функции отрисовки на большом кол-ве элементов вылезает ошибка

Uncaught TypeError: Cannot read property 'x' of undefined
    at drawPoly (Отрисовка.html:16)// в текущем документе - 10
    at HTMLInputElement.onclick (Отрисовка.html:207)

Почему вылезает - не знаю, замучился уже гадать.
Подскажите, пожалуйста, причину, и способ исправить.

Суть второй проблемы: как правильно менять координаты ветки дерева, чтобы точки друг-друга не перекрывали и линии (которые я добавлю позже) не пересекались?
Мое решение, реализованное в коде, пока не проходит (по логике вещей, второй этаж сверху должен рисоваться симметрично, ну и т.д.).
Спасибо.

P.S. Извините за большую пасту, спойлеров не нашел.

рони 13.10.2017 10:28

Цитата:

Сообщение от d1ver
спойлеров не нашел.

[HTML hide run][/HTML]



О том, как вставить в сообщение исполняемый javascript и html-код, а также о дополнительных возможностях форматирования - читайте http://javascript.ru/formatting.

d1ver 13.10.2017 11:05

Спасибо. Отредактировал.

рони 13.10.2017 11:35

Цитата:

Сообщение от d1ver
Cannot read property 'x' of undefined

смотрите как формируются у вас ключи обьекта arr, их просто нет иногда для примера 0, 1, 3,...,9 ключа 2 нет - значит и arr[2].x будет ошибка

рони 13.10.2017 12:11

d1ver,
формировать общий массив точек для каждого уровня и его выводить в одну строку с равными отступами слева и справа.

на счёт не пересечения линий в целом, задача слишком огромная, нужны специальные библиотеки.

Alexandroppolus 13.10.2017 12:25

d1ver,

у тебя метод checkDrawPoint возвращает объект, а не массив.

объект с индексами, которые node.index. И полем length - количеством пунктов. Соответственно, если в перечне индексов будет "дырка", например, индексы (0, 1, 2, 4, ...), то превед undefined.

Либо возвращай нормальный массив (с добавлением туда пунктов с помощью drawPoint.push), либо перебирай его как объект. Имхо, лучше первое.

d1ver 13.10.2017 13:04

Я понимаю, что у меня бывает долго формируется объект, и к пока отсутствующим элементам уже обратиться хотят. Но как это исправить, еще не придумал.
Если подскажете, как, не поймав ту же ошибку, переместить этот объект в массив - скажу большое спасибо, пробовал сразу вносить в массив - и получал эту ошибку.

Alexandroppolus 13.10.2017 16:13

Цитата:

Сообщение от d1ver
Я понимаю, что у меня бывает долго формируется объект, и к пока отсутствующим элементам уже обратиться хотят. Но как это исправить, еще не придумал.

это здесь ни при чем.

объект формируется синхронно, т.е. пока это происходит, никакой другой код выполняться не будет. В onclick все действия синхронные, нет запросов, таймеров и т.д.

поправить надо вот что:
BinarySearchTree.prototype.checkDrawPoint = function() {
    var node = this.root;
    *!*var drawPoint = [];*/!*
    var counter = 0;
    var traverse = function(node) {
        if (!node) return null;
        if (node) {
        	*!*drawPoint.push(node.drawPoint);*/!*
        	counter++;
            traverse(node.left);
            traverse(node.right);
        }
    };
    traverse(node, 0);
    drawPoint.length = counter;
    return drawPoint;
};

d1ver 14.10.2017 02:07

Не пойму, почему, но сработало.
Спасибо, Alexandroppolus.
Объект вмещал в себе все индексы от 0 до конца дерева последовательно, но формировал их не по порядку. Это было критично?

Вот код, все проблемы решил, кому интересно - заглядывайте:

<p data-height="520" data-theme-id="light" data-slug-hash="aLaKWB" data-default-tab="js,result" data-user="IntroD1ver" data-embed-version="2" data-pen-title="aLaKWB" class="codepen">See the Pen <a href="https://codepen.io/IntroD1ver/pen/aLaKWB/">aLaKWB</a> by D1ver (<a href="https://codepen.io/IntroD1ver">@IntroD1ver</a>) on <a href="https://codepen.io">CodePen</a>.</p>
<script async src="https://production-assets.codepen.io/assets/embed/ei.js"></script>


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