Commit 76b82545 authored by D’jalmar Gutierrez Titirico's avatar D’jalmar Gutierrez Titirico 🚲
Browse files

se agrego la opcion de modificar el orden del organigrama

parent de1fea12
......@@ -228,9 +228,9 @@ input[type=checkbox].with-font:checked ~ label:before {
@import 'tiposEntidad/tiposEntidad.scss';
@import '../components/footer/footer.scss';
@import '../components/modal/modal.scss';
@import '../components/organigrama/framework/angular-treant-js/Treant.scss';
@import '../components/organigrama/framework/angular-treant-js/collapsable.scss';
@import '../components/organigrama/framework/angular-treant-js/custom-colored.scss';
@import '../components/organigrama/framework/angular-treant-js/vendor/perfect-scrollbar/perfect-scrollbar.scss';
@import '../components/organigrama/framework/jquery.orgchart.scss';
@import '../components/organigrama/framework/treant-js/Treant.scss';
@import '../components/organigrama/framework/treant-js/collapsable.scss';
@import '../components/organigrama/framework/treant-js/custom-colored.scss';
@import '../components/organigrama/framework/treant-js/vendor/perfect-scrollbar/perfect-scrollbar.scss';
// endinjector
......@@ -34,6 +34,11 @@
tiposCargo: {
method: 'GET',
url: appConfig.serverAddress + '/api/entidades/:id/tiposCargo'
},
ordenarUnidades: {
method: 'PUT',
isArray: true,
url: appConfig.serverAddress + '/api/entidades/:id/ordenarUnidades'
}
})
}
......@@ -48,7 +53,7 @@
return this.resource.get(parametros).$promise;
}
getOrganigrama(id) {
organigrama(id) {
return this.resource.organigrama({id: id}).$promise;
}
......@@ -82,6 +87,10 @@
return this.resource.tiposCargo({id: id}).$promise;
}
ordenarUnidades(id, parametros) {
return this.resource.ordenarUnidades({id: id}, parametros).$promise;
}
}
angular.module('moduloPersonalApp')
......
......@@ -4,55 +4,1451 @@
'use strict';
(()=> {
//region Angular-Treant
class Treant {
static JSONconfig = {
make: function (configArray) {
var i = configArray.length, node;
this.jsonStructure = {
chart: null,
nodeStructure: null
};
//fist loop: find config, find root;
while (i--) {
node = configArray[i];
if (node.hasOwnProperty('container')) {
this.jsonStructure.chart = node;
continue;
}
if (!node.hasOwnProperty('parent') && !node.hasOwnProperty('container')) {
this.jsonStructure.nodeStructure = node;
node.myID = this.getID();
}
}
this.findChildren(configArray);
return this.jsonStructure;
},
findChildren: function (nodes) {
var parents = [0]; // start witha a root node
while (parents.length) {
var parentId = parents.pop(),
parent = this.findNode(this.jsonStructure.nodeStructure, parentId),
i = 0, len = nodes.length,
children = [];
for (; i < len; i++) {
var node = nodes[i];
if (node.parent && (node.parent.myID == parentId)) { // skip config and root nodes
node.myID = this.getID();
delete node.parent;
children.push(node);
parents.push(node.myID);
}
}
if (children.length) {
parent.children = children;
}
}
},
findNode: function (node, nodeId) {
var childrenLen, found;
if (node.myID === nodeId) {
return node;
} else if (node.children) {
childrenLen = node.children.length;
while (childrenLen--) {
found = this.findNode(node.children[childrenLen], nodeId);
if (found) {
return found;
}
}
}
},
getID: (function () {
var i = 0;
return function () {
return i++;
};
})()
};
constructor(jsonConfig, callback) {
if (jsonConfig instanceof Array) {
jsonConfig = Treant.JSONconfig.make(jsonConfig);
}
var newTree = TreeStore.createTree(jsonConfig);
newTree.positionTree(callback);
this.tree_id = newTree.id;
}
static destroy(tree_id) {
TreeStore.destroy(tree_id);
};
}
class ImageLoader {
constructor() {
this.loading = [];
}
processNode(node) {
var images = node.nodeDOM.getElementsByTagName('img'),
i = images.length;
while (i--) {
this.create(node, images[i]);
}
}
removeAll(img_src) {
var i = this.loading.length;
while (i--) {
if (this.loading[i] === img_src) {
this.loading.splice(i, 1);
}
}
}
create(node, image) {
var self = this,
source = image.src;
this.loading.push(source);
function imgTrigger() {
self.removeAll(source);
node.width = node.nodeDOM.offsetWidth;
node.height = node.nodeDOM.offsetHeight;
}
if (image.complete) {
return imgTrigger();
}
UTIL.addEvent(image, 'load', imgTrigger);
UTIL.addEvent(image, 'error', imgTrigger); // handle broken url-s
// load event is not fired for cached images, force the load event
image.src += "?" + new Date().getTime();
}
isNotLoading() {
return this.loading.length === 0;
}
}
class NodeDB {
constructor(nodeStructure, tree) {
this.db = [];
var self = this;
function itterateChildren(node, parentId) {
var newNode = self.createNode(node, parentId, tree, null);
if (node.children) {
newNode.children = [];
// pseudo node is used for descending children to the next level
if (node.childrenDropLevel && node.childrenDropLevel > 0) {
while (node.childrenDropLevel--) {
// pseudo node needs to inherit the connection style from its parent for continuous connectors
var connStyle = UTIL.cloneObj(newNode.connStyle);
newNode = self.createNode('pseudo', newNode.id, tree, null);
newNode.connStyle = connStyle;
newNode.children = [];
}
}
var stack = (node.stackChildren && !self.hasGrandChildren(node)) ? newNode.id : null;
// svildren are position on separate leves, one beneeth the other
if (stack !== null) {
newNode.stackChildren = [];
}
for (var i = 0, len = node.children.length; i < len; i++) {
if (stack !== null) {
newNode = self.createNode(node.children[i], newNode.id, tree, stack);
if ((i + 1) < len) newNode.children = []; // last node cant have children
} else {
itterateChildren(node.children[i], newNode.id);
}
}
}
}
if (tree.CONFIG.animateOnInit) nodeStructure.collapsed = true;
itterateChildren(nodeStructure, -1); // root node
this.createGeometries(tree);
}
createGeometries(tree) {
var i = this.db.length, node;
while (i--) {
this.get(i).createGeometry(tree);
}
}
get(nodeId) {
return this.db[nodeId]; // get node by ID
}
createNode(nodeStructure, parentId, tree, stackParentId) {
var node = new TreeNode(nodeStructure, this.db.length, parentId, tree, stackParentId);
this.db.push(node);
if (parentId >= 0) this.get(parentId).children.push(node.id); //skip root node
if (stackParentId) {
this.get(stackParentId).stackParent = true;
this.get(stackParentId).stackChildren.push(node.id);
}
return node;
}
getMinMaxCoord(dim, parent, MinMax) { // used for getting the dimensions of the tree, dim = 'X' || 'Y'
// looks for min and max (X and Y) within the set of nodes
var parent = parent || this.get(0),
i = parent.childrenCount(),
MinMax = MinMax || { // start with root node dimensions
min: parent[dim],
max: parent[dim] + ((dim == 'X') ? parent.width : parent.height)
};
while (i--) {
var node = parent.childAt(i),
maxTest = node[dim] + ((dim == 'X') ? node.width : node.height),
minTest = node[dim];
if (maxTest > MinMax.max) {
MinMax.max = maxTest;
}
if (minTest < MinMax.min) {
MinMax.min = minTest;
}
this.getMinMaxCoord(dim, node, MinMax);
}
return MinMax;
}
static hasGrandChildren(nodeStructure) {
var i = nodeStructure.children.length;
while (i--) {
if (nodeStructure.children[i].children) return true;
}
}
}
class Tree {
static CONFIG = {
maxDepth: 100,
rootOrientation: 'NORTH', // NORTH || EAST || WEST || SOUTH
nodeAlign: 'CENTER', // CENTER || TOP || BOTTOM
levelSeparation: 30,
siblingSeparation: 30,
subTeeSeparation: 30,
hideRootNode: false,
animateOnInit: false,
animateOnInitDelay: 500,
padding: 15, // the difference is seen only when the scrollbar is shown
scrollbar: 'native', // "native" || "fancy" || "None" (PS: "fancy" requires jquery and perfect-scrollbar)
connectors: {
type: 'curve', // 'curve' || 'step' || 'straight' || 'bCurve'
style: {
stroke: 'black'
},
stackIndent: 15
},
node: { // each node inherits this, it can all be overrifen in node config
// HTMLclass: 'node',
// drawLineThrough: false,
// collapsable: false,
link: {
target: '_self'
}
},
animation: { // each node inherits this, it can all be overrifen in node config
nodeSpeed: 450,
nodeAnimation: 'linear',
connectorsSpeed: 450,
connectorsAnimation: 'linear'
}
};
constructor(jsonConfig, treeId) {
this.id = treeId;
this.imageLoader = new ImageLoader();
this.CONFIG = UTIL.createMerge(Tree.CONFIG, jsonConfig.chart);
this.drawArea = document.getElementById(this.CONFIG.container.substring(1));
this.drawArea.className += " Treant";
this.nodeDB = new NodeDB(jsonConfig.nodeStructure, this);
// key store for storing reference to node connectors,
// key = nodeId where the connector ends
this.connectionStore = {};
}
positionTree(callback) {
var self = this;
if (this.imageLoader.isNotLoading()) {
var root = this.root(),
orient = this.CONFIG.rootOrientation;
this.resetLevelData();
this.firstWalk(root, 0);
this.secondWalk(root, 0, 0, 0);
this.positionNodes();
if (this.CONFIG.animateOnInit) {
setTimeout(function () {
root.toggleCollapse();
}, this.CONFIG.animateOnInitDelay);
}
if (!this.loaded) {
this.drawArea.className += " Treant-loaded"; // nodes are hidden until .loaded class is add
if (Object.prototype.toString.call(callback) === "[object Function]") {
callback(self);
}
this.loaded = true;
}
} else {
setTimeout(function () {
self.positionTree(callback);
}, 10);
}
}
/*
* In a first post-order walk, every node of the tree is
* assigned a preliminary x-coordinate (held in field
* node->flPrelim). In addition, internal nodes are
* given modifiers, which will be used to move their
* children to the right (held in field
* node->flModifier).
*/
firstWalk(node, level) {
node.prelim = null;
node.modifier = null;
this.setNeighbors(node, level);
this.calcLevelDim(node, level);
var leftSibling = node.leftSibling();
if (node.childrenCount() === 0 || level == this.CONFIG.maxDepth) {
// set preliminary x-coordinate
if (leftSibling) {
node.prelim = leftSibling.prelim + leftSibling.size() + this.CONFIG.siblingSeparation;
} else {
node.prelim = 0;
}
} else {
//node is not a leaf, firstWalk for each child
for (var i = 0, n = node.childrenCount(); i < n; i++) {
this.firstWalk(node.childAt(i), level + 1);
}
var midPoint = node.childrenCenter() - node.size() / 2;
if (leftSibling) {
node.prelim = leftSibling.prelim + leftSibling.size() + this.CONFIG.siblingSeparation;
node.modifier = node.prelim - midPoint;
this.apportion(node, level);
} else {
node.prelim = midPoint;
}
// handle stacked children positioning
if (node.stackParent) { // hadle the parent of stacked children
node.modifier += this.nodeDB.get(node.stackChildren[0]).size() / 2 + node.connStyle.stackIndent;
} else if (node.stackParentId) { // handle stacked children
node.prelim = 0;
}
}
}
/*
* Clean up the positioning of small sibling subtrees.
* Subtrees of a node are formed independently and
* placed as close together as possible. By requiring
* that the subtrees be rigid at the time they are put
* together, we avoid the undesirable effects that can
* accrue from positioning nodes rather than subtrees.
*/
apportion(node, level) {
var firstChild = node.firstChild(),
firstChildLeftNeighbor = firstChild.leftNeighbor(),
compareDepth = 1,
depthToStop = this.CONFIG.maxDepth - level;
while (firstChild && firstChildLeftNeighbor && compareDepth <= depthToStop) {
// calculate the position of the firstChild, according to the position of firstChildLeftNeighbor
var modifierSumRight = 0,
modifierSumLeft = 0,
leftAncestor = firstChildLeftNeighbor,
rightAncestor = firstChild;
for (var i = 0; i < compareDepth; i++) {
leftAncestor = leftAncestor.parent();
rightAncestor = rightAncestor.parent();
modifierSumLeft += leftAncestor.modifier;
modifierSumRight += rightAncestor.modifier;
// all the stacked children are oriented towards right so use right variables
if (rightAncestor.stackParent !== undefined) modifierSumRight += rightAncestor.size() / 2;
}
// find the gap between two trees and apply it to subTrees
// and mathing smaller gaps to smaller subtrees
var totalGap = (firstChildLeftNeighbor.prelim + modifierSumLeft + firstChildLeftNeighbor.size() + this.CONFIG.subTeeSeparation) - (firstChild.prelim + modifierSumRight );
if (totalGap > 0) {
var subtreeAux = node,
numSubtrees = 0;
// count all the subtrees in the LeftSibling
while (subtreeAux && subtreeAux.id != leftAncestor.id) {
subtreeAux = subtreeAux.leftSibling();
numSubtrees++;
}
if (subtreeAux) {
var subtreeMoveAux = node,
singleGap = totalGap / numSubtrees;
while (subtreeMoveAux.id != leftAncestor.id) {
subtreeMoveAux.prelim += totalGap;
subtreeMoveAux.modifier += totalGap;
totalGap -= singleGap;
subtreeMoveAux = subtreeMoveAux.leftSibling();
}
}
}
compareDepth++;
if (firstChild.childrenCount() === 0) {
firstChild = node.leftMost(0, compareDepth);
} else {
firstChild = firstChild.firstChild();
}
if (firstChild) {
firstChildLeftNeighbor = firstChild.leftNeighbor();
}
}
}
/*
* During a second pre-order walk, each node is given a
* final x-coordinate by summing its preliminary
* x-coordinate and the modifiers of all the node's
* ancestors. The y-coordinate depends on the height of
* the tree. (The roles of x and y are reversed for
* RootOrientations of EAST or WEST.)
*/
secondWalk(node, level, X, Y) {
if (level <= this.CONFIG.maxDepth) {
var xTmp = node.prelim + X,
yTmp = Y, align = this.CONFIG.nodeAlign,
orinet = this.CONFIG.rootOrientation,
levelHeight, nodesizeTmp;
if (orinet == 'NORTH' || orinet == 'SOUTH') {
levelHeight = this.levelMaxDim[level].height;
nodesizeTmp = node.height;
if (node.pseudo) node.height = levelHeight; // assign a new size to pseudo nodes
}
else if (orinet == 'WEST' || orinet == 'EAST') {
levelHeight = this.levelMaxDim[level].width;
nodesizeTmp = node.width;
if (node.pseudo) node.width = levelHeight; // assign a new size to pseudo nodes
}
node.X = xTmp;
if (node.pseudo) { // pseudo nodes need to be properly aligned, otherwise position is not correct in some examples
if (orinet == 'NORTH' || orinet == 'WEST') {
node.Y = yTmp; // align "BOTTOM"
}
else if (orinet == 'SOUTH' || orinet == 'EAST') {
node.Y = (yTmp + (levelHeight - nodesizeTmp)); // align "TOP"
}
} else {
node.Y = ( align == 'CENTER' ) ? (yTmp + (levelHeight - nodesizeTmp) / 2) :
( align == 'TOP' ) ? (yTmp + (levelHeight - nodesizeTmp)) :
yTmp;
}
if (orinet == 'WEST' || orinet == 'EAST') {
var swapTmp = node.X;