strong optimization

This commit is contained in:
Arsen Mirzaev Tatyano-Muradovich 2022-12-05 11:13:55 +10:00
parent a120ba3491
commit 743ac4f653

356
graph.js
View File

@ -681,9 +681,6 @@ class graph {
* @param {*} hard Увеличить количество итераций для процесса? * @param {*} hard Увеличить количество итераций для процесса?
*/ */
move(x, y, hard = false) { move(x, y, hard = false) {
// console.log(this.element.id, this.pushings && !this.pushings.has(this), this.pullings && !this.pullings.has(this));
console.log(this.element.id, this.pushings, this.pullings);
// Проверка входящих параметров // Проверка входящих параметров
if (typeof x !== 'number') x = this.element.getAttribute('data-x') ?? 0; if (typeof x !== 'number') x = this.element.getAttribute('data-x') ?? 0;
else { else {
@ -793,7 +790,7 @@ class graph {
collision(nodes, hard = false) { collision(nodes, hard = false) {
// Проверка на превышение ограничения по числу итераций у целевого узла // Проверка на превышение ограничения по числу итераций у целевого узла
if (++this.iteration >= this.limit) return this.iteration = 0; if (++this.iteration >= this.limit) return (this.iteration = 0, false);
// Инициализация буфера реестра узлов // Инициализация буфера реестра узлов
const registry = new Set(nodes); const registry = new Set(nodes);
@ -808,325 +805,242 @@ class graph {
// Защита от повторной обработки узла // Защита от повторной обработки узла
if (typeof this.collisions === 'object' && this.collisions.has(node)) continue; if (typeof this.collisions === 'object' && this.collisions.has(node)) continue;
// Инициализация вектора между узлами
let between;
// Инициализация ускорения
let increase = 0;
// Инициализация счётчика итераций // Инициализация счётчика итераций
let iterations = 0; let iterations = 0;
do {
// Произошла коллизия (границы кругов перекрылись)
// Проверка на превышение ограничения по числу итераций у целевого узла
if (++this.iteration >= this.limit) return this.iteration = 0;
// Проверка на превышение ограничения по числу итераций у обрабатываемого узла
if (++node.iteration >= node.limit) return node.iteration = 0;
// Инициализация универсального буфера // Инициализация универсального буфера
let buffer; let buffer;
do {
// Произошла коллизия (границы кругов пересеклись)
// Проверка на превышение ограничения по числу итераций у целевого узла
if (++this.iteration >= this.limit) break;
// Проверка на превышение ограничения по числу итераций у обрабатываемого узла
if (++node.iteration >= node.limit) break;
// Инициализация координат целевого узла // Инициализация координат целевого узла
let x1 = const x1 = (isNaN((buffer = parseInt(node.element.style.left))) ? 0 : buffer) + node.element.offsetWidth / 2;
(isNaN((buffer = parseInt(node.element.style.left))) ? 0 : buffer) + const y1 = (isNaN((buffer = parseInt(node.element.style.top))) ? 0 : buffer) + node.element.offsetHeight / 2;
node.element.offsetWidth / 2;
let y1 =
(isNaN((buffer = parseInt(node.element.style.top))) ? 0 : buffer) +
node.element.offsetHeight / 2;
// Инициализация координат обрабатываемого узла // Инициализация координат обрабатываемого узла
let x2 = const x2 = (isNaN((buffer = parseInt(this.element.style.left))) ? 0 : buffer) + this.element.offsetWidth / 2;
(isNaN((buffer = parseInt(this.element.style.left))) ? 0 : buffer) + const y2 = (isNaN((buffer = parseInt(this.element.style.top))) ? 0 : buffer) + this.element.offsetHeight / 2;
this.element.offsetWidth / 2;
let y2 =
(isNaN((buffer = parseInt(this.element.style.top))) ? 0 : buffer) +
this.element.offsetHeight / 2;
// Реинициализация вектора между узлами // Инициализация вектора между узлами
between = new Victor(x1 - x2, y1 - y2); const between = new Victor(x1 - x2, y1 - y2);
// Узлы преодолели расстояние столкновения? (ограничение выполнения) // Узлы преодолели расстояние столкновения? (ограничение выполнения)
if ( if (
this.actions.collision.current >= this.actions.collision.max ||
between.length() > node.diameter / 2 + this.diameter / 2 || between.length() > node.diameter / 2 + this.diameter / 2 ||
++iterations > (hard ? this.actions.collision.flow.hard : this.actions.collision.flow.medium) ++iterations > (hard ? this.actions.collision.flow.hard : this.actions.collision.flow.medium)
) ) break;
break;
// Инициализация координат вектора (узла с которым произошло столкновение)
let vector = new Victor(x1, y1)
.add(new Victor(between.x, between.y).norm().unfloat())
.subtract(
new Victor(
node.element.offsetWidth / 2,
node.element.offsetHeight / 2
)
);
if (this.actions.collision.current < this.actions.collision.max) {
// Активно столкновение узлов
// Реинициализация реестра обработанных узлов и запись целевого узла // Реинициализация реестра обработанных узлов и запись целевого узла
node.collisions = node.#operator.actions.collision ? new Set([_this]) : null; node.collisions = node.#operator.actions.collision ? new Set([this]) : null;
// Реинициализация счётчиков итераций // Реинициализация счётчиков итераций
node.actions.collision.current = 0; node.actions.collision.current = 0;
// Запись целевого в реестр обработанных узлов в потоке // Инициализация координат вектора (узла с которым произошло столкновение)
node.collisions.add(_this); let vector = new Victor(x1, y1)
.add(new Victor(between.x, between.y).norm().unfloat())
.subtract(new Victor(node.element.offsetWidth / 2, node.element.offsetHeight / 2));
// Перемещение узла // Перемещение узла
node.move(vector.x, vector.y); node.move(vector.x, vector.y);
}
// Проверка на столкновение узлов // Проверка на столкновение узлов
} while ( } while (
this.actions.collision.current < this.actions.collision.max && ++this.actions.collision.current < this.actions.collision.max &&
between.length() <= node.diameter / 2 + this.diameter / 2 between.length() <= node.diameter / 2 + this.diameter / 2
); );
} }
} }
pushing(nodes = [], add, hard = false) { /**
* Обработать отталкивания
*
* @param {*} nodes
* @param {*} add
* @param {*} hard
* @param {*} distance
*
* @returns
*/
pushing(nodes = [], add, hard = false, distance = 100) {
// Проверка на превышение ограничения по числу итераций у целевого узла // Проверка на превышение ограничения по числу итераций у целевого узла
if (++this.iteration >= this.limit) return this.iteration = 0; if (++this.iteration >= this.limit) return (this.iteration = 0, false);
// Инициализация буфера реестра узлов
const registry = new Set(nodes);
// Удаление текущего узла из буфера
registry.delete(this);
// Инициализация ссылки на ядро
const _this = this;
// Увеличение дистанции для проверки
const distance = 100;
// Обработка отталкивания узлов
for (const node of registry) {
// Перебор узлов в буфере реестра
// Защита от повторной обработки узла
if (typeof this.pushings === 'object' && this.pushings.has(node)) continue;
// Инициализация вектора между узлами
let between;
// Инициализация счётчика итераций // Инициализация счётчика итераций
let iterations = 0; let iterations = 0;
function move() {
// Проверка на превышение ограничения по числу итераций у целевого узла
if (++_this.iteration >= _this.limit) return _this.iteration = 0;
// Проверка на превышение ограничения по числу итераций у обрабатываемого узла
if (++node.iteration >= node.limit) return node.iteration = 0;
// Инициализация универсального буфера // Инициализация универсального буфера
let buffer; let buffer;
// Инициализация оператора
const operator = this;
/**
* Оттолкнуть
*
* @param {*} node
*
* @returns {boolean} Узлы преодолели расстояние отталкивания?
*/
function move(node) {
// Защита от повторной обработки узла
if (typeof operator.pushings === 'object' && operator.pushings.has(node)) return false;
// Проверка на превышение ограничения по числу итераций у целевого узла
if (++operator.iteration >= operator.limit) return (operator.iteration = 0, false);
// Инициализация координат целевого узла // Инициализация координат целевого узла
let x1 = const x1 = (isNaN((buffer = parseInt(node.element.style.left))) ? 0 : buffer) + node.element.offsetWidth / 2;
(isNaN((buffer = parseInt(node.element.style.left))) ? 0 : buffer) + const y1 = (isNaN((buffer = parseInt(node.element.style.top))) ? 0 : buffer) + node.element.offsetHeight / 2;
node.element.offsetWidth / 2;
let y1 =
(isNaN((buffer = parseInt(node.element.style.top))) ? 0 : buffer) +
node.element.offsetHeight / 2;
// Инициализация координат обрабатываемого узла // Инициализация координат обрабатываемого узла
let x2 = const x2 = (isNaN((buffer = parseInt(operator.element.style.left))) ? 0 : buffer) + operator.element.offsetWidth / 2;
(isNaN((buffer = parseInt(_this.element.style.left))) const y2 = (isNaN((buffer = parseInt(operator.element.style.top))) ? 0 : buffer) + operator.element.offsetHeight / 2;
? 0
: buffer) +
_this.element.offsetWidth / 2;
let y2 =
(isNaN((buffer = parseInt(_this.element.style.top))) ? 0 : buffer) +
_this.element.offsetHeight / 2;
// Реинициализация вектора между узлами // Инициализация вектора между узлами
between = new Victor(x1 - x2, y1 - y2); const between = new Victor(x1 - x2, y1 - y2);
// Инициализация увеличения // Инициализация увеличения
let increase = const increase =
_this.shift + node.shift + operator.shift + node.shift +
(_this.diameter + node.diameter) / (operator.diameter + node.diameter) /
2 ** (_this.increase + node.increase); 2 ** (operator.increase + node.increase);
// Узлы преодолели расстояние отталкивания? // Узлы преодолели расстояние отталкивания?
if ( if (
_this.actions.pushing.current >= _this.actions.pushing.max ||
between.length() > between.length() >
(node.diameter + _this.diameter) / 2 + (node.diameter + operator.diameter) / 2 +
distance + distance +
increase + increase +
(typeof add === 'number' ? add : 0) || (typeof add === 'number' ? add : 0) ||
++iterations > (hard ? _this.actions.pushing.flow.hard : _this.actions.pushing.flow.medium) ++iterations > (hard ? operator.actions.pushing.flow.hard : operator.actions.pushing.flow.medium)
) ) return true;
return;
// Инициализация координат вектора (узла с которым произошло столкновение)
let vector = new Victor(x1, y1)
.add(new Victor(between.x, between.y).norm().unfloat())
.subtract(
new Victor(
node.element.offsetWidth / 2,
node.element.offsetHeight / 2
)
);
if (_this.actions.pushing.current < _this.actions.pushing.max) {
// Активно притягивание узла
// Реинициализация реестра обработанных узлов и запись целевого узла // Реинициализация реестра обработанных узлов и запись целевого узла
node.pushings = node.#operator.actions.pushing ? new Set([_this]) : null; node.pushings = node.#operator.actions.pushing ? new Set([operator]) : null;
// Реинициализация счётчиков итераций // Реинициализация счётчиков итераций
node.actions.pushing.current = 0; node.actions.pushing.current = 0;
// Инициализация координат обрабатываемого узла (с которым произошло столкновение)
const vector = new Victor(x1, y1)
.add(new Victor(between.x, between.y).norm().unfloat())
.subtract(new Victor(node.element.offsetWidth / 2, node.element.offsetHeight / 2));
// Перемещение узла // Перемещение узла
node.move(vector.x, vector.y); node.move(vector.x, vector.y);
}
// Проверка расстояния // Вход в рекурсию
if ( setTimeout(move, between.length() / 100, node);
_this.actions.pushing.current < _this.actions.pushing.max &&
between.length() <=
(node.diameter + _this.diameter) / 2 +
distance +
increase +
(typeof add === 'number' ? add : 0)
)
return setTimeout(move, between.length() / 100);
} }
// Повторная обработка (вход в рекурсию)
if (_this.actions.pushing.current < _this.actions.pushing.max) move();
}
}
pulling(nodes = [], add, hard = false) {
// Проверка на превышение ограничения по числу итераций у целевого узла
if (++this.iteration >= this.limit) return this.iteration = 0;
// Инициализация буфера реестра узлов // Инициализация буфера реестра узлов
const registry = new Set(nodes); const registry = new Set(nodes);
// Удаление текущего узла из буфера // Удаление текущего узла из буфера
registry.delete(this); registry.delete(this);
// Инициализация ссылки на ядро // Обработка отталкивания
const _this = this; for (const node of registry) if (++this.actions.pushing.current < this.actions.pushing.max) move(node);
}
// Увеличение дистанции для проверки !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! /**
const distance = 150; * Обработать притягивания
*
// Обработка притягивания узлов * @param {*} nodes
for (const node of registry) { * @param {*} add
// Перебор узлов в буфере реестра * @param {*} hard
* @param {*} distance
// Защита от повторной обработки узла *
if (typeof this.pullings === 'object' && this.pullings.has(node)) continue; * @returns
*/
// Инициализация вектора между узлами pulling(nodes = [], add, hard = false, distance = 150) {
let between; // Проверка на превышение ограничения по числу итераций у целевого узла
if (++this.iteration >= this.limit) return (this.iteration = 0, false);
// Инициализация счётчика итераций // Инициализация счётчика итераций
let iterations = 0; let iterations = 0;
function move() {
// Проверка на превышение ограничения по числу итераций у целевого узла
if (++_this.iteration >= _this.limit) return _this.iteration = 0;
// Проверка на превышение ограничения по числу итераций у обрабатываемого узла
if (++node.iteration >= node.limit) return node.iteration = 0;
// Инициализация универсального буфера // Инициализация универсального буфера
let buffer; let buffer;
// Инициализация ссылки на ядро
const operator = this;
/**
* Притянуть
*
* @param {*} node
*
* @returns {boolean} Узлы преодолели расстояние отталкивания?
*/
function move(node) {
// Защита от повторной обработки узла
if (typeof operator.pullings === 'object' && operator.pullings.has(node)) return false;
// Проверка на превышение ограничения по числу итераций у целевого узла
if (++operator.iteration >= operator.limit) return (operator.iteration = 0, false);
// Инициализация координат целевого узла // Инициализация координат целевого узла
let x1 = const x1 = (isNaN((buffer = parseInt(node.element.style.left))) ? 0 : buffer) + node.element.offsetWidth / 2;
(isNaN((buffer = parseInt(node.element.style.left))) ? 0 : buffer) + const y1 = (isNaN((buffer = parseInt(node.element.style.top))) ? 0 : buffer) + node.element.offsetHeight / 2;
node.element.offsetWidth / 2;
let y1 =
(isNaN((buffer = parseInt(node.element.style.top))) ? 0 : buffer) +
node.element.offsetHeight / 2;
// Инициализация координат обрабатываемого узла // Инициализация координат обрабатываемого узла
let x2 = const x2 = (isNaN((buffer = parseInt(operator.element.style.left))) ? 0 : buffer) + operator.element.offsetWidth / 2;
(isNaN((buffer = parseInt(_this.element.style.left))) const y2 = (isNaN((buffer = parseInt(operator.element.style.top))) ? 0 : buffer) + operator.element.offsetHeight / 2;
? 0
: buffer) +
_this.element.offsetWidth / 2;
let y2 =
(isNaN((buffer = parseInt(_this.element.style.top))) ? 0 : buffer) +
_this.element.offsetHeight / 2;
// Реинициализация вектора между узлами // Инициализация вектора между узлами
between = new Victor(x1 - x2, y1 - y2); const between = new Victor(x1 - x2, y1 - y2);
// Инициализация увеличения // Инициализация увеличения
let increase = const increase =
_this.shift + node.shift + operator.shift + node.shift +
(_this.diameter + node.diameter) / (operator.diameter + node.diameter) /
2 ** (_this.increase + node.increase); 2 ** (operator.increase + node.increase);
// Узлы преодолели расстояние притягивания? // Узлы преодолели расстояние притягивания?
if ( if (
_this.actions.pulling.current >= _this.actions.pulling.max ||
between.length() <= between.length() <=
(node.diameter + _this.diameter) / 2 + (node.diameter + operator.diameter) / 2 +
distance + distance +
increase + increase +
(typeof add === 'number' ? add : 0) || (typeof add === 'number' ? add : 0) ||
++iterations > (hard ? _this.actions.pulling.flow.hard : _this.actions.pulling.flow.medium) ++iterations > (hard ? operator.actions.pulling.flow.hard : operator.actions.pulling.flow.medium)
) ) return true;
return;
// Инициализация координат вектора (узла с которым произошло столкновение)
let vector = new Victor(x1, y1)
.add(new Victor(between.x, between.y).norm().invert().unfloat())
.subtract(
new Victor(
node.element.offsetWidth / 2,
node.element.offsetHeight / 2
)
);
if (_this.actions.pulling.current < _this.actions.pulling.max) {
// Активно притягивание узлов
// Реинициализация реестра обработанных узлов и запись целевого узла // Реинициализация реестра обработанных узлов и запись целевого узла
node.pullings = node.#operator.actions.pulling ? new Set([_this]) : null; node.pullings = node.#operator.actions.pulling ? new Set([operator]) : null;
// Реинициализация счётчиков итераций // Реинициализация счётчиков итераций
node.actions.pulling.current = 0; node.actions.pulling.current = 0;
// Инициализация координат обрабатываемого узла (с которым произошло столкновение)
const vector = new Victor(x1, y1)
.add(new Victor(between.x, between.y).norm().invert().unfloat())
.subtract(new Victor(node.element.offsetWidth / 2, node.element.offsetHeight / 2));
// Перемещение узла // Перемещение узла
node.move(vector.x, vector.y); node.move(vector.x, vector.y);
// Вход в рекурсию
setTimeout(move, between.length() / 10 - between.length() / 10, node);
} }
// Проверка расстояния // Инициализация буфера реестра узлов
if ( const registry = new Set(nodes);
_this.actions.pulling.current < _this.actions.pulling.max &&
between.length() >
(node.diameter + _this.diameter) / 2 +
distance +
increase +
(typeof add === 'number' ? add : 0)
)
return setTimeout(
move,
between.length() / 10 - between.length() / 10
);
}
// Повторная обработка (вход в рекурсию) // Удаление текущего узла из буфера
if (_this.actions.pulling.current < _this.actions.pulling.max) move(); registry.delete(this);
}
// Обработка отталкивания
for (const node of registry) if (++this.actions.pulling.current < this.actions.pulling.max) move(node);
} }
configure(attribute) { configure(attribute) {