Skip to content

Instantly share code, notes, and snippets.

@gucheen
Created September 24, 2019 09:37
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save gucheen/439a09bad853691063b2204c26721b5a to your computer and use it in GitHub Desktop.
Save gucheen/439a09bad853691063b2204c26721b5a to your computer and use it in GitHub Desktop.
interface ModernOrgTreeOptions {
container: HTMLElement;
nodes?: NodeList;
parentPosition?: string;
childPosition?: string;
}
export class ModernOrgTree {
parentsPositions = {};
svg;
nodes;
parentPosition;
childPosition;
constructor({container, nodes, parentPosition = 'bottom-center', childPosition = 'top-center'}: ModernOrgTreeOptions) {
this.parentPosition = parentPosition;
this.childPosition = childPosition;
const tag = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
tag.classList.add('modern-org-tree');
tag.style.width = container.scrollWidth.toString() + 'px';
tag.style.height = container.scrollHeight.toString() + 'px';
container.appendChild(tag);
this.svg = tag;
if (nodes) {
this.nodes = nodes;
this.render({nodes});
}
window.addEventListener('resize', () => {
if (this.nodes) {
this.render({nodes: this.nodes});
}
});
}
render({nodes}) {
const container = this.svg.parentNode;
requestAnimationFrame(() => {
this.svg.style.width = '0';
this.svg.style.height = '0';
requestAnimationFrame(() => {
while (this.svg.firstChild) {
this.svg.removeChild(this.svg.firstChild);
}
});
this.parentsPositions = {};
if (nodes) {
this.nodes = nodes;
}
this.nodes.forEach((node) => {
const parentId = node.dataset.parent;
if (parentId) {
if (typeof this.parentsPositions[parentId] === 'undefined') {
const parentElement = document.getElementById(parentId);
if (!parentElement) {
return;
}
const top = parentElement.offsetTop;
const left = parentElement.offsetLeft;
const width = parentElement.offsetWidth;
const height = parentElement.offsetHeight;
const parentPosition = parentElement.dataset.parentPosition || this.parentPosition;
switch (parentPosition) {
case 'right-middle':
this.parentsPositions[parentId] = {y: top + height / 2, x: left + width};
break;
default:
this.parentsPositions[parentId] = {y: top + height, x: left + (width / 2)};
}
}
const px = this.parentsPositions[parentId].x;
const py = this.parentsPositions[parentId].y;
const path = document.createElementNS('http://www.w3.org/2000/svg', 'path');
let pathData;
let x;
let y;
switch (this.childPosition) {
case 'left-middle':
x = node.offsetLeft;
y = node.offsetTop + (node.offsetHeight / 2);
pathData = `M ${px} ${py} L ${px} ${y} L ${x} ${y}`;
break;
default:
x = node.offsetLeft;
y = node.offsetTop + (node.offsetHeight / 2);
const v = (py + y) / 2;
pathData = `M ${px} ${py} L ${px} ${v} L ${x} ${v} L ${x} ${y}`;
}
path.setAttribute('d', pathData);
path.setAttribute('stroke', '#0287FF');
path.setAttribute('fill', 'none');
requestAnimationFrame(() => {
this.svg.appendChild(path);
});
}
});
this.svg.style.width = container.scrollWidth.toString() + 'px';
this.svg.style.height = container.scrollHeight.toString() + 'px';
});
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment