added options for nodes generation and block some events

This commit is contained in:
Arsen Mirzaev Tatyano-Muradovich 2022-11-26 07:38:23 +10:00
parent 7bb1772164
commit c3a8dad9de

233
graph.js
View File

@ -1,6 +1,6 @@
import Victor from "https://cdn.skypack.dev/victor@1.1.0"; import Victor from "https://cdn.skypack.dev/victor@1.1.0";
("use strict"); 'use strict';
/** /**
* @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy> * @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy>
@ -97,40 +97,152 @@ class graph {
// Инициализация HTML-элемента узла // Инициализация HTML-элемента узла
const article = document.createElement("article"); const article = document.createElement("article");
article.id = operator.nodes.size; article.id = operator.nodes.size;
article.classList.add("node", "unselectable"); article.classList.add(data.color ?? 'white', "node", "unselectable");
if (typeof data.href === "string") { if (typeof data.href === "string") {
article.href = data.href; article.href = data.href;
} }
// Инициализация заголовка-ссылки // Инициализация заголовка
const title = document.createElement("a"); const title = document.createElement("h4");
title.innerText = data.title ?? data.link ?? "Неизвестно"; title.classList.add('title');
if (typeof data.link === "string") title.href = data.link; title.innerText = data.title ?? null;
// Запись в оболочку // Запись в оболочку
article.appendChild(title); article.appendChild(title);
if (typeof data.description === "string") { // Инициализация описания
// Найдено описание узла const description = document.createElement("div");
description.classList.add('description');
description.title = data.popup ?? null;
// Инициализация заголовка /**
const description = document.createElement("p"); * Показать описание
description.innerText = data.description; */
description.style.display = "none"; function show() {
article.setAttribute( // Отображение описания
"onclick", description.style.display = null;
"const description = this.getElementsByTagName('p')[0]; description.style.display === 'none' ? description.style.display = null : description.style.display = 'none'"
);
// Запись в оболочку // Расположение выше остальных узлов
article.appendChild(description); article.style.zIndex = 1000;
}
/**
* Скрыть описание
*/
function hide() {
// Скрытие описания
description.style.display = 'none';
// Удаление расположения выше других узлов
article.style.zIndex = null;
}
// Запись блокировки открытия описания в случае, если был перемещён узел
title.onmousedown = (onmousedown) => {
// Запись открытия описания
title.onclick = (onclick) => { show() }
title.onmousemove = (onmousemove) => {
// Курсор сдвинут более чем на 15 пикселей?
if (Math.abs(onmousedown.pageX - onmousemove.pageX) > 15 || Math.abs(onmousedown.pageY - onmousemove.pageY) > 15) {
// Запись иконки курсора
title.style.cursor = 'grabbing';
// Запись события для возврата иконки курсора
title.onmouseup = fn => {
// Удаление событий
title.onmouseup = title.onmousemove = null;
// Удаление иконки курсора
title.style.cursor = null;
}
title.onclick = (onclick) => { return false }
} else title.onclick = (onclick) => { show() }
}
};
// Запись в оболочку
article.appendChild(description);
// Инициализация левой фигуры для обёртки текста
const left = document.createElement("span");
left.classList.add('left', 'wrapper');
// Запись в описание
description.appendChild(left);
// Инициализация правой фигуры для обёртки текста
const right = document.createElement("span");
right.classList.add('right', 'wrapper');
// Запись в описание
description.appendChild(right);
// Инициализация ссылки на источник
const a = document.createElement("a");
a.innerText = typeof data.link === 'object' && typeof data.link.name === 'string' ? data.link.name : null;
a.href = typeof data.link === 'object' && typeof data.link.href === 'string' ? data.link.href : null;
a.classList.add(...(typeof data.link === 'object' && typeof data.link.class === 'object' ? data.link.class : []));
a.title = typeof data.link === 'object' && typeof data.link.title === 'string' ? data.link.title : null;
// Блокировка событий браузера (чтобы не мешать переноса узла)
a.ondragstart = a.onselectstart = fn => { return false };
// Запись блокировки перехода по ссылке в случае, если был перемещён узел
a.onmousedown = (onmousedown) => {
a.onmousemove = (onmousemove) => {
// Курсор сдвинут более чем на 15 пикселей?
if (Math.abs(onmousedown.pageX - onmousemove.pageX) > 15 || Math.abs(onmousedown.pageY - onmousemove.pageY) > 15) {
// Запись иконки курсора
a.style.cursor = 'grabbing';
// Запись события для возврата иконки курсора
a.onmouseup = fn => {
// Удаление событий
a.onmouseup = a.onmousemove = null;
// Удаление иконки курсора
a.style.cursor = null;
}
a.onclick = (onclick) => { return false }
} else a.onclick = (onclick) => { return true }
}
};
// Запись в описание
description.appendChild(a);
// Запись текста в описание
const text = document.createElement("p");
text.innerText = data.description ?? null;
// Запись в оболочку
description.appendChild(text);
if (
typeof data.cover === "string"
) {
// Получены другие HTML-элементы
// Инициализация левой фигуры для обёртки текста
const cover = document.createElement("img");
cover.src = data.cover;
cover.alt = data.title ?? null;
cover.classList.add('cover', 'unselectable');
// Запись в описание
description.appendChild(cover);
} }
if ( if (
typeof data.append === "HTMLCollection" || typeof data.append === "HTMLCollection" ||
typeof data.append === "HTMLElement" typeof data.append === "HTMLElement"
) { ) {
// Найдены другие HTML-элементы узла // Получены другие HTML-элементы
// Запись в оболочку // Запись в оболочку
article.appendChild(data.append); article.appendChild(data.append);
@ -139,6 +251,15 @@ class graph {
// Запись в документ // Запись в документ
operator.shell.appendChild(article); operator.shell.appendChild(article);
// Запись диаметра описания в зависимости от размера заголовка (чтобы вмещался)
description.style.width = description.style.height = (a.offsetWidth === 0 ? 50 : a.offsetWidth) * 3 + 'px';
// Запись отступа заголовка (чтобы был по центру описания)
a.style.left = description.offsetWidth / 2 - a.offsetWidth / 2 + 'px';
// Сокрытие описания (выполняется после расчёта размера потому, что иначе размер будет недоступен)
description.style.display = "none";
// Запись в свойство // Запись в свойство
this.#element = article; this.#element = article;
@ -151,11 +272,11 @@ class graph {
// Перемещение // Перемещение
this.move( this.move(
operator.shell.offsetWidth / 2 - operator.shell.offsetWidth / 2 -
this.#diameter / 2 + this.#diameter / 2 +
(0.5 - Math.random()) * 500, (0.5 - Math.random()) * 500,
operator.shell.offsetHeight / 2 - operator.shell.offsetHeight / 2 -
this.#diameter / 2 + this.#diameter / 2 +
(0.5 - Math.random()) * 500, (0.5 - Math.random()) * 500,
true, true,
true, true,
true true
@ -174,6 +295,14 @@ class graph {
this.element.style.width = this.element.style.height = this.element.style.width = this.element.style.height =
this.#diameter + "px"; this.#diameter + "px";
// Инициализация описания
const description = this.element.getElementsByClassName('description')[0];
// Запись отступа описания (чтобы был по центру узла)
description.style.display = null;
description.style.marginLeft = description.style.marginTop = (this.element.offsetWidth - description.offsetWidth) / 2 + 'px';
description.style.display = 'none';
// Инициализация ссылки на ядро // Инициализация ссылки на ядро
const _this = this; const _this = this;
@ -501,10 +630,10 @@ class graph {
if ( if (
!node.actions.pushing || !node.actions.pushing ||
between.length() > between.length() >
(node.diameter + _this.diameter) / 2 + (node.diameter + _this.diameter) / 2 +
distance + distance +
increase + increase +
(typeof add === "number" ? add : 0) || (typeof add === "number" ? add : 0) ||
--iterations <= 0 --iterations <= 0
) )
return; return;
@ -539,10 +668,10 @@ class graph {
if ( if (
node.actions.pushing && node.actions.pushing &&
between.length() <= between.length() <=
(node.diameter + _this.diameter) / 2 + (node.diameter + _this.diameter) / 2 +
distance + distance +
increase + increase +
(typeof add === "number" ? add : 0) (typeof add === "number" ? add : 0)
) )
setTimeout(move, between.length() / 100); setTimeout(move, between.length() / 100);
} }
@ -632,10 +761,10 @@ class graph {
if ( if (
!node.actions.pulling || !node.actions.pulling ||
between.length() <= between.length() <=
(node.diameter + _this.diameter) / 2 + (node.diameter + _this.diameter) / 2 +
distance + distance +
increase + increase +
(typeof add === "number" ? add : 0) || (typeof add === "number" ? add : 0) ||
--iterations <= 0 --iterations <= 0
) )
return; return;
@ -669,10 +798,10 @@ class graph {
if ( if (
node.actions.pulling && node.actions.pulling &&
between.length() > between.length() >
(node.diameter + _this.diameter) / 2 + (node.diameter + _this.diameter) / 2 +
distance + distance +
increase + increase +
(typeof add === "number" ? add : 0) (typeof add === "number" ? add : 0)
) )
return setTimeout( return setTimeout(
move, move,
@ -715,8 +844,8 @@ class graph {
? value === "true" ? value === "true"
? true ? true
: value === "false" : value === "false"
? false ? false
: value : value
: buffer; : buffer;
} }
} }
@ -790,22 +919,22 @@ class graph {
line.setAttribute( line.setAttribute(
"x1", "x1",
(isNaN((buffer = parseInt(from.element.style.left))) ? 0 : buffer) + (isNaN((buffer = parseInt(from.element.style.left))) ? 0 : buffer) +
from.element.offsetWidth / 2 from.element.offsetWidth / 2
); );
line.setAttribute( line.setAttribute(
"y1", "y1",
(isNaN((buffer = parseInt(from.element.style.top))) ? 0 : buffer) + (isNaN((buffer = parseInt(from.element.style.top))) ? 0 : buffer) +
from.element.offsetHeight / 2 from.element.offsetHeight / 2
); );
line.setAttribute( line.setAttribute(
"x2", "x2",
(isNaN((buffer = parseInt(to.element.style.left))) ? 0 : buffer) + (isNaN((buffer = parseInt(to.element.style.left))) ? 0 : buffer) +
to.element.offsetWidth / 2 to.element.offsetWidth / 2
); );
line.setAttribute( line.setAttribute(
"y2", "y2",
(isNaN((buffer = parseInt(to.element.style.top))) ? 0 : buffer) + (isNaN((buffer = parseInt(to.element.style.top))) ? 0 : buffer) +
to.element.offsetHeight / 2 to.element.offsetHeight / 2
); );
line.setAttribute("stroke", "grey"); line.setAttribute("stroke", "grey");
line.setAttribute("stroke-width", "8px"); line.setAttribute("stroke-width", "8px");
@ -851,14 +980,14 @@ class graph {
this.element.children[0].setAttribute( this.element.children[0].setAttribute(
x, x,
(isNaN((buffer = parseInt(node.element.style.left))) ? 0 : buffer) + (isNaN((buffer = parseInt(node.element.style.left))) ? 0 : buffer) +
node.element.offsetWidth / 2 node.element.offsetWidth / 2
); );
// Запись отступа (координаты по вертикали) // Запись отступа (координаты по вертикали)
this.element.children[0].setAttribute( this.element.children[0].setAttribute(
y, y,
(isNaN((buffer = parseInt(node.element.style.top))) ? 0 : buffer) + (isNaN((buffer = parseInt(node.element.style.top))) ? 0 : buffer) +
node.element.offsetHeight / 2 node.element.offsetHeight / 2
); );
} }
}; };
@ -911,7 +1040,7 @@ class graph {
}; };
}; };
// Перещапись событий браузера (чтобы не дёргалось) // Блокировка событий браузера (чтобы не дёргалось)
_this.shell.ondragstart = null; _this.shell.ondragstart = null;
} }
} }
@ -943,7 +1072,7 @@ class graph {
// Начало переноса // Начало переноса
// Позиционирование над остальными узлами // Позиционирование над остальными узлами
node.element.style.zIndex = 550; node.element.style.zIndex = 5000;
if (!_this.#camera) { if (!_this.#camera) {
// Запрещено двигать камеру (оболочку) // Запрещено двигать камеру (оболочку)
@ -960,9 +1089,9 @@ class graph {
// Перемещение // Перемещение
node.move( node.move(
onmousemove.pageX - onmousemove.pageX -
(onmousedown.pageX - n.left + s.left + pageXOffset), (onmousedown.pageX - n.left + s.left + pageXOffset),
onmousemove.pageY - onmousemove.pageY -
(onmousedown.pageY - n.top + s.top + pageYOffset), (onmousedown.pageY - n.top + s.top + pageYOffset),
true, true,
true, true,
true true
@ -983,7 +1112,7 @@ class graph {
node.actions.collision = node.actions.pushing = node.actions.pulling = true; node.actions.collision = node.actions.pushing = node.actions.pulling = true;
// Позиционирование вместе остальными узлами // Позиционирование вместе остальными узлами
node.element.style.zIndex = 500; node.element.style.zIndex = null;
}; };
}; };